I am creating my first iOS application, which theoretically should be quite simple, but I am having difficulty making it bulletproof enough for me to confidently present it in the App Store.
In short, there is a tabular view on the main screen, after selecting a row that goes into another tabular view that displays information related to the selected row in master part mode. The underlying data is retrieved as JSON data from the web service once a day, and then cached in the master data store. Data preceding this day is deleted to stop the SQLite database file indefinitely. All data storage operations are performed using Core Data with the NSFetchedResultsController underlying the presentation of the detail table.
The problem I see is that if you switch between the main and detailed screens several times, while the fresh data is extracted, analyzed and saved, the application completely freezes or crashes. There seems to be some kind of race condition, possibly due to importing Core Data data in the background, while the main thread is trying to fetch, but I'm thinking. I am having trouble writing any meaningful alarm data, usually SIGSEGV in depth to the master data stack.
The following table shows the actual order of events that occur when the detail table view controller loads:
Main Thread Background Thread
viewDidLoad
Get JSON data (using AFNetworking)
Create child NSManagedObjectContext (MOC)
Parse json data
Insert managed objects in child MOC
Save child MOC
Post import completion notification
Receive import completion notification
Save parent MOC
Perform fetch and reload table view
Delete old managed objects in child MOC
Save child MOC
Post deletion completion notification
Receive deletion completion notification
Save parent MOC
As soon as the AFNetworking termination block starts when JSON data arrives, NSManagedObjectContext is created and embedded in the importer object, which parses the JSON data and stores the objects in the master data store. The importer performs using the new performBlock method introduced in iOS 5:
NSManagedObjectContext *child = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [child setParentContext:self.managedObjectContext]; [child performBlock:^{
The importer object monitors its own MOC NSManagedObjectContextDidSaveNotification , and then sends its own notification, which is observed by the detail table view controller. When this notification is published, the table view controller saves its own (parent) MOC.
I use the same basic template with the “deleter” object to delete old data after importing new data for the day. This happens asynchronously after new data has been obtained using the selected result controller, and the detail table view has been reloaded.
One thing I don’t do is to observe any merge notifications or block any of the managed object contexts or the permanent repository coordinator. Is this something I have to do? I'm a little unsure how to archive this correctly, so I would appreciate any advice.