Search code examples
iosmultithreadingcore-datadeadlockafincrementalstore

Deadlock using AFIncrementalStore and NSFetchedResultsController


I've been bashing my head against this for a few days now and cannot for the life of me figure out what is going on. I'm pretty green with Core Data, but I know it well enough to avoid deadlock scenarios. However for this project I decided to try and incorporate AFIncrementalStore. I built a sample project to test the APIClient in order to map keys/values appropriately without messing with my actual project. It worked flawlessly.

Now I'm using it in my actual project and things are finicky. The NSFetchedResultsController is used in a UITableViewController that gets pushed off screen (slide in menu similar to Facebook app). About 50% of the time I don't get a deadlock. I've made sure that the NSFetchedResultsController managedObjectContext is the same as my AppDelegate. Nearly everything is setup identical to the AFIncrementalStore examples. Even my sample project to test out the usage works perfectly.

Here is an image of the Debug Navigator when I pause during the deadlock. It looks like the problem lies between AFIncrementalStore's background context and the main thread's context. However I'm not sure what to do since I didn't write AFIncrementalStore and am just going off of the existing docs/examples.

Debug Navigator

edit: Adding the backtrace of the 2nd thread

thread #2: tid = 0x2103, 0x925d180e libsystem_kernel.dylib`semaphore_wait_trap + 10
frame #0: 0x925d180e libsystem_kernel.dylib`semaphore_wait_trap + 10
frame #1: 0x0258cf08 libdispatch.dylib`_dispatch_thread_semaphore_wait + 16
frame #2: 0x0258ab3a libdispatch.dylib`_dispatch_barrier_sync_f_slow + 149
frame #3: 0x0258aa5c libdispatch.dylib`dispatch_barrier_sync_f + 37
frame #4: 0x00b64c8b CoreData`_perform + 187
frame #5: 0x00b67659 CoreData`-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:] + 73
frame #6: 0x00bdf2db CoreData`__97-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:]_block_invoke_0 + 75
frame #7: 0x00b64cc1 CoreData`internalBlockToNSManagedObjectContextPerform + 17
frame #8: 0x0259b014 libdispatch.dylib`_dispatch_client_callout + 14
frame #9: 0x0258ad5f libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 58
frame #10: 0x0258aaa3 libdispatch.dylib`dispatch_barrier_sync_f + 108
frame #11: 0x00b64c8b CoreData`_perform + 187
frame #12: 0x00b67659 CoreData`-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidUnregisterObjectsWithIDs:] + 73
frame #13: 0x00b71c8c CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _disposeObjects:count:notifyParent:] + 444
frame #14: 0x00b71305 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _dispose:] + 597
frame #15: 0x00b70e15 CoreData`-[NSManagedObjectContext _dealloc__] + 325
frame #16: 0x00bd872f CoreData`internalBlockToDeallocNSManagedObjectContext + 79
frame #17: 0x0259b014 libdispatch.dylib`_dispatch_client_callout + 14
frame #18: 0x0258b418 libdispatch.dylib`_dispatch_queue_drain + 239
frame #19: 0x0258b2a6 libdispatch.dylib`_dispatch_queue_invoke + 59
frame #20: 0x0258c280 libdispatch.dylib`_dispatch_root_queue_drain + 231
frame #21: 0x0258c450 libdispatch.dylib`_dispatch_worker_thread2 + 39
frame #22: 0x971cde12 libsystem_c.dylib`_pthread_wqthread + 441

Solution

  • I'm not a CoreData expert by any means, so take this with a grain of salt.

    It looks like, possibly, you are using the NSPrivateQueueConcurrencyType. It appears that AFIncrementalStore is using the main queue for synchronization. Is that under your control?

    Can you try switching your NSManagedObjectContext to NSMainQueueConcurrencyType and see if that helps?

    Now, if I'm right and you are using NSPrivateQueueConcurrencyType, you're probably doing it for a performance reason. So, this might not be a great long-term solution...