Reputation: 20569
I have an NSOperationQueue on my main thread running a set of NSOperations (max concurrent set to 1) that I want to be able to cancel at any time. When I press a button I tell the queue to cancel all operations and wait until finished. This should hang the main thread until the operation queue is empty, however it is hanging my main thread indefinitely.
Here's the code I use to stop it:
...
[myQueue cancelAllOperations];
[myQueue waitUntilAllOperationsAreFinished];
return YES; // This line never gets called
Note: I need to use waitUntilAllOperationsAreFinished
as further processes require that the queue be empty.
The strange thing is this is only occurring on the device. When running in the simulator it works as expected.
I have watched breakpoints and I can follow the currently running operation until it finishes. It detects [self isCancelled], stops what it's doing and zips through to the end of the main
method. I can see that nothing in the operation is causing it to hang, and by cancelling all operations, none of the other operations should start, and the queue should finish. I have checked by adding breakpoints and none of the other operations start.
Why is this happening?
Upvotes: 4
Views: 8018
Reputation: 75058
You should never, ever block the main thread. It handles all your UI updates for one thing, for another as you have noted you managed to create a deadlock.
Instead, try creating a method like:
- (void) notifyOnFinish
{
[myQueue waitUntilAllOperationsAreFinished];
[self performSelectorOnMainThread:(queueEmpty) withObject:nil waitUntilDone:NO];
}
Then where you have your code now, call:
[myQueue cancelAllOperations];
[self performSelectorInBackground:@selector(notifyOnFinish) withObject:nil];
And in a queueEmpty method you just do whatever you want to do when the queue is emptied.
Basically, just create a background thread to block instead of the main thread.
Upvotes: 5
Reputation: 170319
In any of your operations (or in any other thread), are you using -performSelectorOnMainThread:withObject:waitUntilDone:
? -waitUntilAllOperationsAreFinished
will block whatever thread it's called on until all operations are complete. Odds are, if you're calling this as the application is terminating, that thread would be the main thread. If the main thread is blocked, and one of the operations uses -performSelectorOnMainThread:withObject:waitUntilDone:
, your application will freeze because the operation will never complete.
I've had this exact thing happen to me before. Unfortunately, it's pretty difficult to work around.
Upvotes: 8
Reputation: 58448
Perhaps the waitUntilAllOperationsArefFinished
is causing the block... Maybe the operations all cancel and finish before the call to waitUntilAllOperationsArefFinished
and then the queue is sat hanging, waiting for operations that are already finished to finish...?
I don't know this for a fact, but maybe try not calling waitUntilAllOperationsArefFinished
.
Upvotes: 0