0

I have an image in Core Data. It has to be saved as NSData, and I have a computed property to get and set the image based on the Core Data property imageData:

var image: UIImage? {
    get {
        if let imageData = imageData {
            return UIImage(data: imageData)
        } else {
            return nil
        }
    }

    set {
        if let image = image {
            imageData = UIImagePNGRepresentation(image)
        } else {
            imageData = nil
        }
    }
}

However, I believe that this code will convert between UIImage and NSData every time the image is fetched, which can be very often since this data is used to populate a UITableViewCell. Is this true, or is Xcode smart enough to cache computed properties in some way? Also, is this the recommended way of fetching images from Core Data, or is it recommended to fetch it once and save it to a new property like this (unsure if this code is correct):

lazy var image: UIImage? = {
        if let imageData = imageData {
            return UIImage(data: imageData)
        } else {
            return nil
        }
}()

The downside of the last one the way I see it is that it would be possible to change imageData without image being updated. I'm also not sure if I can just use didSet in the latter version to update Core Data.

Jorn
  • 1,054
  • 9
  • 25
  • [look at this git repo](https://github.com/romainmenke/SimpleCam) It displays images from CoreData in a table. It is asynchronous and does not fetch the images in the cell, but in a separate method. [how to : images & coredata](http://stackoverflow.com/questions/27995955/saving-picked-image-to-coredata/27996685#27996685) – R Menke Jun 06 '16 at 19:03

1 Answers1

1

Assuming that imageData is a property of the entity description,

  • The managed object context will cache imageData.
  • The image will not be cached, and will be recomputed every time.

If you're going to store images in Core Data, the right approach is simpler than you're making it. UIImage conforms to NSCoding, which means you can just create an image attribute with the Core Data "transformable" type. Core Data will then automatically invoke NSCoding methods to convert to/from UIImage and you don't need any of the code in your question. You just read/write your UIImage.

If you're going to store images in Core Data, using any scheme, make sure that the images aren't too large. Core Data can handle them but you may find that the image data gets loaded when you don't expect. For example, if you're only using other non-image attributes of a managed object, but the image data gets loaded anyway.

Tom Harrington
  • 69,312
  • 10
  • 146
  • 170
  • Also, mark the image attribute with "External Storage" in the model editor if the images are large. – Mundi Jun 06 '16 at 19:57
  • @Mundi unfortunately that's (still!) not an option for transformable attributes. – Tom Harrington Jun 06 '16 at 22:08
  • Right, thanks for pointing that out! I guess another solution worth being pointed out is then to use `NSData` as the property type, choose "External Storage" and write a convenience method to retrieve the image. This would be very close to OP's solution. – Mundi Jun 09 '16 at 11:47
  • Thank you. This solution sounds great, but I fail at implementing this. When I set my image property to transformable in Core Data and generate an `NSManagedObject`, it gets the type `NSObject?`. If I just assign `myImageView.image = myTransformableProperty`, I obviously get an error message saying that I cannot assign a value of type `NSObject?` to type `UIImage?`. How can I fix this? – Jorn Jun 11 '16 at 14:28
  • Ahh, never mind. I changed NSObject? to UIImage? and everything works! – Jorn Jun 11 '16 at 14:43