Core Data: Can a Large Background Fetch Block Fetch Request on the Main Thread?
I have an iPad app with quite a bit of text data in Core Data (approx 75MB). New data is imported weekly. The import happens on a secondary thread with its own NSManagedObjectContext and even its own NSPersistentStoreCoordinator.
The import process contains a number of fetches, all of which are very efficient except one, as it returns a vast number of records (this can perhaps be optimized slightly more, but not materially so.) Unfortunately, during the time the开发者_如何学运维 large fetch is made, the main UI is blocked (as it also has to fetch from the store and the fetch is delayed).
I have tested the import process at various points to confirm that it is indeed on a background thread. I have double checked code to ensure the import context with the separate coordinator is used. The undomanager is nil and the import context is reset frequently.
Is it possible that even with a separate NSPersistentStoreCoordinator a large fetch request in the background can still block fetch requests on the main thread or am I doing something wrong?
An operation on a background thread cannot block the main thread but it can consume so much memory that the main thread can longer operate efficiently.
It sounds like your numerous background fetches which "returns a vast number of records" is creating a large object graph of live objects in memory which is eating your memory. The low memory impedes the main thread.
Use Instruments to profile your memory to confirm.
The solution is to keep only the actual live, populated objects in memory you absolutely have to. You can use smaller fetches, fetch as faults, fetch properties or fetch as managedObjectIDs and similar methods to reduce the memory footprint.
Also, make sure your network operations that download the data itself don't eat memory or cycles.
Sounds like you're already dealing with threading correctly (though you do'nt technically need a new NSPersistentStoreCoordinator per thread, as long as you have a NSManagedObjectContext per thread).
Your large fetch sounds like the problem; have you looked at NSFetchedResultsController to batch the results?
If you already have then you need to find some way of optimizing your query - what is the NSPredicate you are using for the large fetch?
The other approach might be to offload your text data into flat files and just keep the filename in core data - this would reduce the amount of data you need to write, therefore blocking other threads for a shorter amount of time.
You could just add a method to your NSManagedObject subclass that got the text on request from the file - your UI shouldn't know how you are storing your text!
as it also has to fetch from the store and the fetch is delayed
This is exactly the culprit, so, depending on your circumstances, the answer may be a definitive yes. Specifically, if your large fetch happens on the same store as any other fetches, subsequent fetches will be blocked until the first one completes.
One tactic in this case is to pre-fetch, with returnsObjectsAsFaults = NO
, any objects you're likely to use during the massive fetch.
Is it possible that even with a separate NSPersistentStoreCoordinator a large fetch request in the background can still block fetch requests on the main thread
In this case it should not block - but as you note in your question there are other factors which can cause a block. This solution has its own problems re: integrating changes, but if you can merge the two coordinators then it works in principal.
精彩评论