I have a UITableView that gets data from an NSFetchedResultsController
. To this end, i basically copied Apples example implementation from https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/nsfetchedresultscontroller.html.
Now at WWDC16 Apple announced the UITableViewDataSourcePrefetching
protocol, which provides callbacks that let you prefetch data so it's already loaded when it's needed to be displayed by the tableview. I'm looking for an example on how to integrate this with the NSFetchedResultsController
, because i can't figure out if i'm doing this correctly.
cellForRowAtIndexPath
instead of querying fetchedResultsController.object(at: indexPath)
directly?fetchedResultsController.object(at: indexPath)
in the prefetch callbacks, to ensure the data gets cached?*edit*: I found a slide from the Core Data talk at WWDC16 that supposedly explains this, but i understand it at all.
NSFetchedResultsController
. I guess that's why it's performed on the managedObjectContext
directly?.performFetch()
on the NSFetchedResultsController
. Nothings showing up until i call that. But since all the results are there after calling it, i don't get why i would need to prefetch them again.It will improve performance if your model has faults. Whether your models have faults or not depends on iOS optimization, and how you create your schema and relationships.
So to be safe your could add the prefetch code. I have the code for Swift 4.
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
let fetchRequest: NSFetchRequest<MyModel> = MyModel.fetchRequest()
fetchRequest.returnsObjectsAsFaults = false
let items = indexPaths.map { fetchedResultsController.object(at: $0) }
fetchRequest.predicate = NSPredicate(format: "SELF IN %@", items)
let asyncFetchRequest = NSAsynchronousFetchRequest(fetchRequest: fetchRequest)
do {
try fetchedResultsController.managedObjectContext.execute(asyncFetchRequest)
} catch { }
}
What it does is pretty self explanatory. It runs an async fetch request on the managed object context, therefore resolving faults, if any.
In short, you are creating a custom predicate to "warm" the predicted specific objects in the MOC. The idea, I think, is that the table view is telling you more targeted scroll target info (based on velocity etc.) about where it thinks the table view will end up. This allows you to execute an async request to pre-fetch these objects in the MOC so that by the time you are actually asking for properties on it, they're ready to go.
This is why you also have a nil
completion on the async request. You aren't directly using the results because you may not actually be displaying any of these index paths yet. It also means it's unnecessary to do additional tracking (like in a Dictionary
, etc.) of results when you get pre-fetched objects.
The real question is, if you are using an FRC with batching, pre-fetched properties, etc., is this really buying you anything to side-step it? I'm not really sure. I haven't noticed a huge difference between a pretty highly tuned FRC+UITableView
with vs without pre-fetching on a table of around 1000 results. It's also possible by merely touching those objects that the FRC will see that (because you are sharing the same MOC) and then will run through it's property/relationship pre-fetching, etc. I haven't seen much documentation on this mechanism, but if Apple is suggesting it, especially using an FRC, I have to think it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With