I am getting EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) on dispatch_semaphore_dispose but don't really know how to track down the root cause of this. My code makes use of dispatch_async, dispatch_group_enter and so on.
UPDATE: The cause of the crash is due to the fact that the webserviceCall (see code below) never calls onCompletion and when the code is run again, I got the error EXC_BAD_INSTRUCTION. I verified this is indeed the case, but not sure why or how to prevent this.
Code:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
for (...) {
if (...) {
dispatch_group_enter(group);
dispatch_async(queue, ^{
[self webserviceCall:url onCompletion:^{
dispatch_group_leave(group);
}];
});
}
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)));
dispatch_sync(queue, ^{
// call completion handler passed in by caller
});
});
From your stack trace, EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
occurred because dispatch_group_t
was released while it was still locking (waiting for dispatch_group_leave
).
According to what you found, this was what happened :
dispatch_group_t group
was created. group
's retain count = 1.-[self webservice:onCompletion:]
captured the group
. group
's retain count = 2.dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... });
captured the group
again. group
's retain count = 3.group
was released. group
's retain count = 2.dispatch_group_leave
was never called.dispatch_group_wait
was timeout. The dispatch_async
block was completed. group
was released. group
's retain count = 1.-[self webservice:onCompletion:]
was called again, the old onCompletion
block was replaced with the new one. So, the old group
was released. group
's retain count = 0. group
was deallocated. That resulted to EXC_BAD_INSTRUCTION
.To fix this, I suggest you should find out why -[self webservice:onCompletion:]
didn't call onCompletion
block, and fix it. Then make sure the next call to the method will happen after the previous call did finish.
In case you allow the method to be called many times whether the previous calls did finish or not, you might find someone to hold group
for you :
DISPATCH_TIME_FOREVER
or a reasonable amount of time that all -[self webservice:onCompletion]
should call their onCompletion
blocks by the time. So that the block in dispatch_async(...)
will hold it for you.group
into a collection, such as NSMutableArray
.I think it is the best approach to create a dedicate class for this action. When you want to make calls to webservice, you then create an object of the class, call the method on it with the completion block passing to it that will release the object. In the class, there is an ivar of dispatch_group_t
or dispatch_semaphore_t
.