Search code examples
multithreadingswiftcore-datansoperationqueue

Core Data NSManagedObjectContext save never returns when called from a background queue


My app (unit test) is stalling when I call save() in an NSManagedObjectContext's private queue, originating from a separate background queue. It is a normal Core Data stack (with an in-memory persistent store for the unit tests).

Isn't the whole point of a private-queue context that you shouldn't be concerned about what queue an operation comes from? How should I resolve this?

I haven't been able to reproduce it in isolation, but here's a rough idea of my setup (pseudo-Swift, condensing calls across multiple classes):

let store = inMemoryStoreCoordinator()

let mainContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
mainContext.persistentStoreCoordinator = store

let childContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
childContext.parentContext = mainContext

let q = NSOperationQueue()
let group = dispatch_group_create()

q.addOperationWithBlock {
    dispatch_group_enter(group)
    childContext.performBlock {
        try! childContext.save()
        dispatch_group_leave(group)
    }
}

dispatch_group_wait(group, DISPATCH_TIME_FOREVER)

Solution

  • I realized what's causing the deadlock. I'm using a dispatch group to lock the main thread, and apparently when the child context goes to save to its parent context (a Main Queue context), that's causing the deadlock.