0

Imagine you use a web service that delivers images via an API. Every image has an UID and you have a Core Data entity Image with attributes uid (int) and image (transformable).

Now a gallery of your app needs to show many images (the UIDs are known). You don't know which of the images have been downloaded and stored before. How can you lazily download images with core data in the background, so that the view may show an UIActivityIndicator during loading and automatically shows the image as soon as it is stored locally (e.g. by using the NSFetchedResultsControllerDelegate protocol)?

Is it useful to subclass UIImageView for that purpose?

Norbert
  • 4,239
  • 7
  • 37
  • 59
  • You want to store the image itself as a NSData object in your Core Data database? – runmad Sep 02 '12 at 20:34
  • Yes, exactly. For the purpose of downloading it only once. But it's uncertain if that image is already in the database. Until it's cached, a place holder needs to be shown and being replaced by the real image as soon as it's available. – Norbert Sep 02 '12 at 20:39

3 Answers3

3
  1. Yes, you can use Core Data for this, but be forewarned that there is a performance hit when you use Core Data to store images. It's negligible if you're dealing with small (e.g. thumbnail) images, but for very large images, the performance hit is observable. For large images, I'd store the images in Documents folder (or, better, a subfolder), and use Core Data to keep track of what images have been downloaded, their filenames, etc. But if the images are smaller, keeping everything right there in Core Data is cleaner.

  2. I probably would not want to use a subclassed UIImageView for this purpose, because you might want to decouple the presentation layer (the image view) from the caching of images. Also, for sophisticated user interfaces, UIImageView objects may be discarded or reused as the user scrolls through a big collection of images, so you might not want a hard link between the UIImageView and your caching logic. Also, depending upon your user interface, sometimes the images can dictate something broader than the UIImageView (e.g., if you're using a tableview, you might want to adjust the cell height based upon the image as it's downloaded). The particulars of the implementation of what the UI might do depend upon where the image is being used (a UITableView, a UIScrollView that is showing a grid of images, etc.).

So, bottom line, for simple user interfaces, perhaps you could subclass a UIImageView but I'd generally advise to have some custom image caching object that does the lazy loading with some delegate protocol to tell the UI when the image load is complete.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Up to which size do you regard images as small? The biggest images will have up to 100 kB (or max. screen filling, not zoomable). I've found this [answer](http://stackoverflow.com/a/2573113/176248) which tells that it's no problem to store images that size within a separate entity. – Norbert Sep 03 '12 at 08:01
  • @Norbert It's completely up to you. Personally, my threshold is radically different than that answer, because for me, if it's larger than a thumbnail (e.g. more than 10-20kb), I'd put in `Documents` folder. I did some benchmarking at one point, and found a 30-40% performance hit for using Core Data, rather than `Documents`. My app used entirely 100-300 kb files, and I got a discernible performance improvement when I went to `Documents`. And, if performance is critical, doing some intelligent caching (I use a NSCache instead of NSMutableDictionary) is important. – Rob Sep 03 '12 at 10:04
  • Try repeatedly retrieving image from Core Data using `imageWithData` and then from Documents using `imageWithContentsOfFile` (not `imageNamed`) and compare the results. A few months ago, I benchmarked sqlite (admittedly, slightly different than Core Data) v `Documents`, and for thumbnails, I could retrieve 10,000 times from `Documents` in 13 seconds on iPhone 4S, and in 23 seconds from sqlite. As you can see, the difference is observable, but with thumbnails like this, each is fast enough that it might not matter. As images get bigger, though, it starts to make a difference. – Rob Sep 03 '12 at 10:13
2

I wouldn't use Core Data to store images, but I'd store them on disk. I was trying to find in the documentation where Apple themselves warn against storing images larger than 100k or so in Core Data since you'd run into a performance issue.

However, I found this article that talks about Core Data Image Caching that may be of use.

Also, here's another Stack Overflow post with a good answer that tells you when to store images in a database and when to just use references to disk storage.

Community
  • 1
  • 1
runmad
  • 14,846
  • 9
  • 99
  • 140
0

If you don't absolutely need Core Data, then may I recommend using MWPhotoBrowser?

https://github.com/mwaterfall/MWPhotoBrowser

It essential generates a gallery view controller for you which you can push onto your navigation controller. The gallery view controller has scrollable images with pinch zoom, pan, everything, even emailing the photo to someone.

It also does the lazy loading of the image with the activity indicator.

Short answer: everything you wanted to do without reinventing the wheel.

Zhang
  • 11,549
  • 7
  • 57
  • 87