JMD JMD - 1 year ago 99
iOS Question

dispatch_async block on main queue is never execeuted

I have an app that uses a connection queue that handles the connections on a background thread. Each connection sends a JSON post, then when it receives a success, saves some objects into coredata.

Once all connections are complete, i call a

on the main thread to call a

However, under very specific conditions of data im sending/saving, I've noticed the
block to the main thread never gets called, and the app screen freezes, all execution stops, and the app sits idle with a frozen screen. processing power according to xcode is 0%.

Here is method with the block that fails.

- (void)connectionDidComplete

_syncProgress = (float)_completeConnections / (float)_totalConnections;

dispatch_async(mainQueue, ^(void) {
[[NSNotificationCenter defaultCenter] postNotificationName:SyncQueueDidUpdateNotification object:nil];
}); <-- this dispatch works

if (_completeConnections == _totalConnections)
// clear unsynced data
NSArray *syncedObjects = [SyncObject completedSyncObjects];

if (syncedObjects.count > 0)
for (SyncObject *syncObject in syncedObjects)
[syncObject delete];

//this method saves the current context, then merges this context with the main context right after
[[VS_CoreDataManager sharedManager] saveManagedObjectContextAndWait:managedObjectContext];

// cleanup the thread's context
[[VS_CoreDataManager sharedManager] unRegisterManagedObjectContextForThread:currentThread];
managedObjectContext = nil;

// complete sync
dispatch_async(mainQueue, ^(void) {
[self performSelector:@selector(finishSync) withObject:nil afterDelay:2];
}); <-- this dispatch never gets called

My suspicion is this problem has something to do with saving the context then merging it. And possibly while that is happening its released in the middle of the merge, causing some weird hang up and the dispatch isn't getting executed. This is just a guess though, and I don't know how to fix it.

Any ideas?


Answer Source

If the block on the main thread is not executed, then it is because of 1 of 2 reasons.

  1. The main thread is blocked; is not processing any events at all. Got a while() loop on the main thread? That'd do it. A lock? There you go.

  2. The main thread is running a modal run loop inside the outer run loop. Asynchronous dispatches to the main event loop -- main thread -- won't be processed in this case.

Set a breakpoint on that dispatch_async() and see what the main thread is doing (at the point of dispatch the main thread is most likely already in the bad state).

DarkDust's suggestion of using dispatch_after() is a good one, but is unlikely to work in that it is almost assuredly the case that your main thread is not processing events when the problem occurs. I.e. fix the problem, then move to dispatch_after() as DarkDust suggests.