I am trying to understand the cause of this accident in order to better understand how the blocks behave. I have a really simple class to trigger this crash.
@implementation BlockCrashTest - (void)doSomething { dispatch_queue_t queue = dispatch_queue_create("com.queue.test", DISPATCH_QUEUE_SERIAL); __weak typeof(self) weakSelf = self; dispatch_block_t block = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; dispatch_group_t group = dispatch_group_create(); dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC); dispatch_group_enter(group); [strongSelf performSomethingAsync:^{ dispatch_group_leave(group); }]; if(dispatch_group_wait(group, time) != 0) { NSLog(@"group already finished"); } }; dispatch_async(queue, block); } - (void)performSomethingAsync:(void(^)(void))completion { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(5); completion(); }); } - (void)dealloc { NSLog(@"released object"); } @end
Now, if I select a class and just call doSomething ,
BlockCrashTest *someObject = [[BlockCrashTest alloc] init]; [someObject doSomething];
It crashes with the exception EXC_BAD_INSTRUCTION and monitors the stack trace,
#0 0x000000011201119a in _dispatch_semaphore_dispose ()
If I modify the doSomething method so that it does not use weak , but uses self, then the crash does not occur, and the methods seem to execute as expected.
- (void)doSomething { dispatch_queue_t queue = dispatch_queue_create("com.queue.test", DISPATCH_QUEUE_SERIAL); dispatch_block_t block = ^{ dispatch_group_t group = dispatch_group_create(); dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC); dispatch_group_enter(group); [self performSomethingAsync:^{ dispatch_group_leave(group); }]; if(dispatch_group_wait(group, time) != 0) { NSLog(@"group already finished"); } }; dispatch_async(queue, block); }
Why is this a failure, I understand that using the weak inside the block will ensure that the method will not be called if the object is released, and I thought the weak is safer than using self inside the block.
The code above works fine with weakSelf if I save the BlockCrashTest object and call its method.
I would be very happy if someone could explain the cause of the accident, and what exactly happens with these three different code variants above that one failure and the others seem to work fine.
Note. This is somehow related to the crash pointed to by the thread, Objective-C crash on __destroy_helper_block_ . I was able to reproduce the exact stack traces with my code above.