Reputation: 3919
Let's say I have a basic iPhone app that maintains contacts. I have an entity named "Contact" that has the attributes "name", "address" and "photo". The app's main view is just a table view that displays the name of each contact. The user can then click on each name to display the corresponding photo and address (in a separate view controller).
The problem is, photos can have a very large size.
Isn't it the case that when I fetch managed objects, all of its attributes also get brought into memory? In this case, it could take a long time to load the app and display the names in the table view, because the app is also underneath fetching all the photos (and addresses), right?
For this reason, wouldn't you say that I should—in order to make the main view more snappy (and the app faster to load)—make a new "ContactFacade" entity which has only the "name" attribute and a relationship to a "Contact" entity that contains further details about that contact?
Upvotes: 0
Views: 475
Reputation: 16463
Apple has a small section on their Core Data Performance page called "Large Data Objects (BLOBs)". The part of interest is:
For small to modest sized BLOBs (and CLOBs), you should create a separate entity for the data and create a to-one relationship in place of the attribute.
I have seen great performance improvements in my app after implementing this change. However, I was in a situation where I needed to fetch 300+ objects in a single request for displaying on a map. In your situation you can use a NSFetchedResultsController
to manage the data in your table, and this will limit the fetches to a small subset of your data.
Upvotes: 0
Reputation: 4339
Enchilada,
Large BLOBs should always be in "leaf" entities. A "leaf entity only contains the NSData BLOB and the inverse relation. This also allows you to easily exploit iOS v5/Mac OS X Lion's automatic BLOB saving in the filesystem. By doing this, you can control explicitly when they are loaded. Just as importantly, by using -refreshObject:mergeChanges:
judiciously, you can force the BLOBs from your memory and, potentially, the row cache. This one change will dramatically improve your fetch and loading performance.
One caveat to depending upon Core Data's file mapping for large BLOBs is that it doesn't use memory mapping to open the large file. This will hit your resident footprint in memory. You will need to explicitly unload these BLOBs when the memory warnings come, and they will come.
Andrew
Upvotes: 1
Reputation: 33379
Instead of storing the images in core data, store them as files on the disk and only store the filename in core data.
If you use UIImage to read an image from a file, it will automatically remove itself from ram and load itself back into ram, as necessary.
If you want really good performance, you should make sure the images are smaller, or perhaps have two sizes (thumb and full size).
Also, pay attention to what image format you should use. PNG will use more disk space, but it requires less CPU time to render than a JPEG.
Upvotes: 4
Reputation: 1048
Core data figures this stuff out for you - it will not fetch all the photos and such until you actually need to show them. The UI will not block.
For excellent example, check out the Stanford iOS class in iTunes U, specifically the Core Data lecture and Core Data demo (lectures 13 and 14). They even have a CoreDataTableViewController that you can easily hook up to your FetchResultsController, which I have been using in my current project.
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/node/289
The example app there not only displays large photos, it does it efficiently from the network.
Enjoy,
Damien
Upvotes: 1