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 groupwas created.group‘s retain count = 1.-[self webservice:onCompletion:]captured thegroup.group‘s retain count = 2.dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... });captured thegroupagain.group‘s retain count = 3.- Exit the current scope.
groupwas released.group‘s retain count = 2. dispatch_group_leavewas never called.dispatch_group_waitwas timeout. Thedispatch_asyncblock was completed.groupwas released.group‘s retain count = 1.- You called this method again. When
-[self webservice:onCompletion:]was called again, the oldonCompletionblock was replaced with the new one. So, the oldgroupwas released.group‘s retain count = 0.groupwas deallocated. That resulted toEXC_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 :
- You can change the timeout from 2 seconds to
DISPATCH_TIME_FOREVERor a reasonable amount of time that all-[self webservice:onCompletion]should call theironCompletionblocks by the time. So that the block indispatch_async(...)will hold it for you.
OR - You can add
groupinto a collection, such asNSMutableArray.
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.