46

I have an application where I allow the user to add an image for their account.

I wish to know how to store an image (obtained from the camera or photo library) using Core Data, as I may offer a backup facility for the user and would be looking to transfer the image data to a server.

I have come across the design suggestion of creating an Image model object and creating a 1-to-1 relationship with the User model object (so that the associated Image object is not called up unless required). However, I am unsure how to practically store the image and whether this is potentially fatal in terms of performance.

I would be grateful for any advice on the approach and pitfalls from anyone who has attempted this.

Urizen
  • 2,331
  • 6
  • 23
  • 33

4 Answers4

84

The rule for storing image data in Core Data is as follows:

  • < 100 kb store in the related entity (person, address, whatever).
  • < 1 mb store in a separate entity on the other end of a relationship to avoid performance issues.
  • 1 mb store on disk and reference the path in your Core Data store.

You can use the transformable data type to store the NSImage directly into Core Data. In fact you can use the transformable data type to store anything that implements the NSCoder protocol.

Personally I would not convert it to a CGImageRef as you can lose a lot of information that way.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
  • I'm confused, are you saying that you wouldn't store an image to a core data entity using a transformable data type? – memmons Mar 10 '11 at 03:13
  • No. I am saying that depending on the size of the image you will want to store it either in a separate entity or on disk. Large images cause issues with the cache. – Marcus S. Zarra Mar 10 '11 at 19:40
  • 2
    There are some exciting new ways to save you from that hassle in iOS5. Check the docs, it's still under NDA. – steipete Sep 01 '11 at 11:31
  • @steipete What's the best way to replicate that property-whose-name-cannot-be-spoke in iOS <5 – Alexsander Akers Sep 01 '11 at 21:40
  • 8
    @steipete Now that iOS5 is not under NDA, I assume you were referring to the new "...external storage for attribute values. If you specify that the value of a managed object attribute may be stored as an external record, Core Data heuristically decides on a per-value basis whether it should save the data directly in the database or store a URI to a separate file that it manages for you." – Richard Venable Dec 04 '11 at 13:16
  • The link for getting Core Data to decide on what to do with large assets (allowsExternalBinaryDataStorage) is here: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSAttributeDescription_Class/reference.html#//apple_ref/occ/instm/NSAttributeDescription/allowsExternalBinaryDataStorage – nevan king Apr 13 '12 at 18:55
  • @RichardVenable I've been using this to store images on a few apps, and it does seem to have it's issues. Have you been using it successfully? What's your experience with it? – Philippe Sabourin Apr 18 '12 at 18:18
  • 2
    FYI, external storage does not work on iOS. It is a desktop only flag. – Marcus S. Zarra Apr 18 '12 at 22:12
  • 2
    I have been using the external storage flag on one small app, and it seemed to be working fine, but I guess, according to Marcus, it isn't doing anything. I guess that means the photos I am saving are just saved as big blobs in my database. I wish Apple would have told me that! – Richard Venable Apr 18 '12 at 23:44
  • 3
    Its a small footnote in the documentation, shocked me when I found it also. – Marcus S. Zarra Apr 19 '12 at 03:43
  • Do you mean 'UIImage', not 'NSImage'? –  May 24 '12 at 11:30
30

Time passed since this question was asked but I want to share my experience regarding this issue.


I wouldn't recommend you storing images inside your DB if their number is not limited. You should keep in mind that someday you'll add a new version of the data model and you'll have to migrate from old DB to a new one on App update. It takes time. The bigger you DB file is longer it takes to migrate.

If you want to store images in DB be sure you don't add a persistent store in application: didFinishLaunchingWithOptions: method of UIApplicationDelegate. iOS will terminate your app if migration won't complete in XX seconds.

Eldar Markov
  • 950
  • 9
  • 13
  • 1
    Big thank you +1 for that comment :-) – PeterK Jul 31 '12 at 10:02
  • Can you post a reliable source reference to the comment you made about "iOS will terminate your app if migration won't complete in 30 seconds"? – Pavan Nov 09 '14 at 11:52
4

Pitfall: You may end up huge, hard to handle sqlite database. Do you really want your users to upload a several MB file in one step to the server? What do you do, if the celluar connection breaks down for some seconds?

I think it would be better, if you use Core Data for managing your images and their upload state (uploaded: yes or no). This way, you can upload the images, when it fits in your application workflow. Okay, it will last a bit longer, because of the many connections. But is a cleaner approach, I think...

When you think about iTunes, when speaking of backups: Your local iPhone 'Documents' folder is synced anyway.

Stefan
  • 28,843
  • 15
  • 64
  • 76
  • Thank you for the answer. I may go down the route of simply storing the path as a string and then counting on iTunes to provide the backup of the image file (while storing the other account related data on the remote server). – Urizen Jan 19 '10 at 09:45
3

You would have to have a a a, then you can could do something like this:

CGImageRef imageRef = uiImage.CGImage;
CGDataProviderRef dataProvider = CGImageGetDataProvider(imageRef);
NSData *imageData = (NSData*)CGDataProviderCopyData(dataProvider);
[managedObject setValue:imageData forKey:@"data"];

Where managedObject is your core data image object and @"data" is the name of the binary property. You might also need to save the image format in order to deserialize the image later.

Another option is to save the image to disk and store the path in core data.

Elfred
  • 3,851
  • 22
  • 16
  • also, release imageData when you are done. – Elfred Jan 19 '10 at 01:17
  • Also check out using a Transformable Attribute: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html – Nimrod Jan 19 '10 at 02:39
  • Sorry, I know this might seem like a basic question but how do you go about (and what is meant by) saving the image format? I've not come accross this idea before. – Urizen Jan 19 '10 at 09:42
  • I'm refering to storing the fact that the image is a jpg or png (or some other format). You will need this info when you fetch the image data from the database in order to select the right data provider to convert it to a CGImageRef. – Elfred Jan 19 '10 at 14:34