Tôi đã cố gắng hiểu lý do đằng sau vụ tai nạn này để hiểu thêm về cách hoạt động của các khối. Tôi có một lớp học thực sự đơn giản để kích hoạt vụ tai nạn này.Tai nạn với dispatch_block
@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
Bây giờ, nếu tôi bố trí các lớp và chỉ cần gọi phương thức doSomething với nó,
BlockCrashTest *someObject = [[BlockCrashTest alloc] init];
[someObject doSomething];
Nó bị treo với ngoại lệ, EXC_BAD_INSTRUCTION và chồng sau dấu vết,
#0 0x000000011201119a in _dispatch_semaphore_dispose()
#1 0x0000000112013076 in _dispatch_dispose()
#2 0x0000000112026172 in -[OS_dispatch_object _xref_dispose]()
#3 0x000000010ef4c2fd in __29-[BlockCrashTest doSomething]_block_invoke at /Users/Sandeep/Desktop/Test Block Crash/Test Block Crash/ViewController.m:35
#4 0x0000000112005ef9 in _dispatch_call_block_and_release()
Nếu tôi sửa đổi phương thức doSomething, như vậy mà nó không sử dụng yếu nhưng sử dụng tự sau đó vụ tai nạn không xảy ra và các phương pháp dường như thực hiện như mong đợi,
- (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);
}
Tại sao nó sụp đổ, sự hiểu biết của tôi là sử dụng yếu bên trong khối sẽ chắc chắn rằng phương pháp sẽ không được gọi, nếu đối tượng được phát hành và tôi nghĩ rằng yếu là an toàn hơn sử dụng tự bên trong khối.
Đoạn mã trên hoạt động tốt với weakSelf, nếu tôi giữ lại các đối tượng BlockCrashTest và gọi phương thức với nó.
Tôi sẽ thực sự hạnh phúc nếu ai đó có thể giải thích lý do đằng sau vụ tai nạn và chính xác những gì xảy ra với 3 biến thể mã khác nhau ở trên mà một sự cố và dường như hoạt động tốt.
Lưu ý: Đây là bằng cách này hay khác có liên quan đến vụ tai nạn được liệt kê trong chủ đề, Objective-C crash on __destroy_helper_block_. Tôi đã có thể tạo lại chính xác các dấu vết ngăn xếp với mã của tôi ở trên.
Bạn cũng có thể cho tôi một đầu mối về lý do tại sao nó không sụp đổ, nếu tôi sử dụng tự bên trong khối? Có phải chỉ vì khối đó vẫn giữ nguyên bản thân? – Sandeep
@GeneratorOfOne - Bởi vì sự hiện diện của 'self' thiết lập tham chiếu mạnh mẽ bên trong khối, mà không được giải quyết cho đến khi khối được thực hiện xong. Vì vậy, 'weakSelf' không phải là' nil' và 'strongSelf' cũng không phải là' nil'. Vì vậy, khối xử lý hoàn thành của bạn trong 'performSomethingAsync' đang được gọi, đảm bảo rằng" enter "bây giờ được cân bằng bởi" leave ". Nhưng nếu bạn muốn khối giữ lại đối tượng, bạn rõ ràng sẽ không trải qua điệu nhảy yếu/chính mình. – Rob
Đây là giải thích tốt. Vì vậy, tôi có thể có một số đối tượng autoreleased mà vẫn có thể làm một số cuộc gọi không đồng bộ dài và vẫn còn xung quanh nếu tôi sử dụng tự, thay vì sử dụng yếu/mạnh. Trong khi nếu đối tượng là nếu giữ lại chính nó, sau đó nó có ý nghĩa để có yếu/mạnh mẽ, là ý chính của điều này? – Sandeep