rnystrom
rnystrom

Reputation: 1916

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

Upvotes: 2

Views: 1542

Answers (2)

tapi
tapi

Reputation: 1736

This issue is not specific to the use of AFIncrementalStore. We've encountered the same thing with just using nested contexts and the NSFetched results controller.

Child and Sibling contexts do not need to use the same concurrency types should not need to use the same thread. However, your fetched results controller must be used on the same thread that its managed object context uses, That thread 2 NSManagedObjectContext Queue in your debug navigator makes me think this probably is a threading issue.

if this is your main context some times this is as simple as wrapping your fetth like this

dispatch_async(dispatch_get_main_queue(), ^{ [resultsController performFetch:nil]; });

or for the truly paranoid

[_resultsController.managedObjectContext performBlock:^{
    [_resultsController performFetch:nil];
}];

There's plenty of stuff on these deadlocks, try here and here for over stack overflow posts.

Upvotes: 4

Mattie
Mattie

Reputation: 3028

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...

Upvotes: 2

Related Questions