Fetching large number of data from CoreData using two NSFetchedResultsController - uitableview

I am trying to fetch 10000records from CoreData in a UITableView using NSFetchedResultsController and trying to make it as fast as possible (since the request has a sort descriptor it takes longer to fetch this amount of data).
I am trying to fetch 100records from CoreData with the first and main NSFetchedResultsController(used in the delegate methods of the table), that is displayed on the table while in another queue I started in viewDidAppear another fetch for all 10000records on an auxiliarFRC. After the fetch in the AuxFRC ends, I assign to the main FRC the AuxFRC so all the records get transfered and I reload the table.
My problem is that the UITableView gets stuck at the first loaded rows till the AuxFRC ends the fetch even if I dispatch the performFetch, and I can not understand why this happens, or if this way is wrong what other way can be used to fetch 10000records and stay up to date if the data changes?

I guess the problem was the NSManagedObjectContext - that is not thread safe and I used the same one for both the fetches. I created a copy of the original one and changed the AuxFRC on the second context. This solved everything.

The trick is to use the cache mechanism of FRC and coordinate the asynchronous fetch with the display thread.
All is summarised in this answer.

Related

SwiftUI - How can I know when my FetchedResults changes?

I'd like to pass to my model the newest fetched data of my core data entities, in order to have them synched.
Is this possible?
The reason is that I have many variables that have to be calculated from the data saved in core data. These values are used in my views, so they should update at the same time.
(Until now I just found a way to pass them around every time with functions, but I find this very chaotic...)
Until now:
func doSomethingWithFetchedData(fetchedData: FetchedResults<Entity>) {
//return what I need
}
Thanks!
NSFetchedResultsController Subscribing to updates for many objects matching a fetch request has been easier than subscribing to updates from a single managed object, thanks to NSFetchedResultsController. It comes with a delegate that informs us about changes to the underlying data in a structured way, because it was designed to integrate with tables and collection views
Here is a good link to start with

Scrolling tableview while updating its datasource fetched from CoreData crash

Here is my context:
When I launch my app I fetch local data from CoreData and fill a tableview with it. At the same time I send an asynchronous request to my webservice to fetch what will be the new content of my tableview.
As soon as the request sends me a response I delete all the instances of the current NSManagedObjects and create new ones with the new data I got. Then I replace the datasource of my tableview to an array of the new NSManagedObjectContexts instances.
My problem:
I'm getting an error : CoreData could not fulfill a fault for ... if I scroll my tableview when the request finished and is triggering the deletion/creation of my tableview's data source.
I understand that this problem occurs because I'm trying to access an old NSManagedObject instance while doesn't exist anymore as it is explained in the doc : Apple doc. But I have no idea of what are the best practices in my case.
I don't want to block the user until my request finished but I have to prevent any error if he accesses "old" data while the request didn't finish (e.g : what if the user taps on a cell and I pass an instance of an NSManagedObject to another viewcontroller but when the request finishes this object doesn't exist anymore ?)
I would appreciate any help !
I highly recommend you to use NSFetchedResultsController since it's sole purpuse is:
You use a fetched results controller to efficiently manage the results returned from a Core Data fetch request to provide data for a UITableView object.
When using a fetched results controller it is much easier to handle the Core Data events like insert, delete, update.
You say you have three sections in your table view? That's no problem, NSFetchedResultsController can handle all of that.
Take a look at this. Apple provides a very nice set of instructions on how to configure and use NSFetchedResultsController.

Core Data - Trying to prefetch attributes for all rows is slow

I'm displaying some images in a collection view, and using SDWebImage to prefetch thumbnails for all of them.
I'm using a batch size of 20 in the NSFetchRequest, but when iterating over every object to get the url of the image I need, the batch size performance gain is wasted. Reloading the data takes 0.3s instead of 0.000295s, which results in a obvious delay in the UI.
I've tried setting [request setPropertiesToFetch:#[#"propertyName"]] but it doesn't seem to make a difference. I guess it's not the method I'm looking for.
Any suggestions ?
Edit:
I am using using an UICollectionView backed by a NSFetchedResultsController (and delegate) data-source. I am making a NSFetchRequest with a batch size of 20 and fetching it via the NS-FRC. I also need to get the list of urls from ALL the fetched objects, ie:
for(NSManagedObjectSubclass *object in frc.fetchedObjects)
// this is causing the slow-down, because it's faulting all the objects
// not what you'd want if you have many objects!
{
[urlList addObject:(object.url)]
}
[SDWebImagePrefetcher prefetchUrls:urlList];
// this runs in the background and downloads/gets from cache a list of images
See NSFetchRequest's class reference, -setPropertiesToFetch:. "This value is only used if resultType is set to NSDictionaryResultType."
You're correct that iterating over all of the fetched objects kills the benefit of the small batch size. I'm curious, though, why you need to prefetch all of the image URLs at once. If you're doing this to trigger a download, look into doing that in -awakeFromFetch: pass the object.url off to your SDWebImagePrefetcher, which will enqueue the request and start or continue processing. You'll have to subclass NSManagedObject to do this.

CoreData load big data

I would like to hear other options on how to load big data(large number of rows - 100000) from a SQL store with CoreData in a user friendly(without blocking the UI) manner on iOS.
Currently I am doing this:
Make the fetch on a secondary thread on a managed context named B for example
Notify the UI thread that the data was loaded
Send the reloadData message to a UITableView to display the new data
In the table datasource methods I get the data from the B context using the managedObjectID and the method objectWithID on the context A which is the main context or UI context in my case.
Doing this sometimes I feel that is not the best approach so I would like to hear other options from you.
Thank you for your help! :)
Try to do it on the main thread using NSFetchedResultsController and set the batchSize to a smaller value (e.g. 200)
If you do not need change monitoring, set NSDictionaryResultType for retch request. Then you will get NSDictionary and you won't need to fetch objects from context A again.

NSFectchedResultsController's delegate not firing on inserts

I have 2 NSFectchedResultsController for 2 Entities which populates the tableView fine.
If I remove an object, it is removed fine.
If I add an object to the first NSFectchedResultsController, it works fine, but does not work fine with the second NSFectchedResultsController.
The object is being added NSManagedContext in the background thread for both entities. The are being updated deleted and inserted on the same background thread for both entities.
So I am really confused to why the insert/update don't work on the second NSFetchController.
thanks for your help
Each FRC will have a fetch request set to a single entity. The FRC will respond only to changes that affect its particular entity and then only if you have the FRC delegate properly configured.
You need to make sure that the managed object context used by the second FRC (if different from the one used by first FRC) receives the merge notifications from the background thread.

Resources