这种崩溃相当罕见,但它经常发生足以让我相信我做错了。
这是一个在自定义并发队列上使用主线程异步调度和屏障调度执行的 API 调用(使用屏障是因为我们正在修改在其他地方读取的数据,通过对同一队列的非屏障调用)。
目标是异步发出 HTTP 请求,然后触发 dispatch_barrier_async 来处理结果数据。
当 dispatch_barrier_async 调用复制传递的块中使用的变量时,就会发生崩溃。我想该变量在块中使用之前已被释放,但考虑到我如何声明它(作为 __block 变量)我不知道这是怎么发生的(除非问题出在另一边赋值运算符...)。
这是堆栈跟踪:
#0 0x00004f44 in __Block_byref_object_copy_ at /blah/ABEvent.m:156
#1 0x0000582d in __copy_helper_block_ at /blah/ABEvent.m:191
#2 0x02cf3be2 in _Block_call_copy_helper ()
#3 0x02cf3681 in _Block_copy_internal ()
#4 0x02c25526 in _dispatch_Block_copy ()
#5 0x02c26802 in dispatch_barrier_async ()
#6 0x00004e71 in __18+[ABEvent fetch]_block_invoke at /blah/ABEvent.m:159
#7 0x00056e77 in __88-[ABClient get:parameters:success:failure:]_block_invoke_2 at /blah/ABClient.m:375
#8 0x02c2553f in _dispatch_call_block_and_release ()
#9 0x02c37014 in _dispatch_client_callout ()
#10 0x02c277d5 in _dispatch_main_queue_callback_4CF ()
#11 0x02facaf5 in __CFRunLoopRun ()
#12 0x02fabf44 in CFRunLoopRunSpecific ()
#13 0x02fabe1b in CFRunLoopRunInMode ()
#14 0x02f517e3 in GSEventRunModal ()
#15 0x02f51668 in GSEventRun ()
#16 0x01ef1ffc in UIApplicationMain ()
#17 0x0005164d in main at /blah/main.m:3
#18 0x00002db5 in start ()
和代码:
+ (void)fetch {
ABBlock _success = ^(ABMessage *m) {
__block NSMutableArray *fetched = [NSMutableArray arrayWithArray:m.params[@"live"]];
[fetched addObjectsFromArray:m.params[@"soon"]]; // EXC_BAD_ACCESS (top of stack)
dispatch_barrier_async([ABEvent eventQueue], ^{ // CRASHED IN BLOCK INVOKE (stack line 6)
NSMutableArray *events = [NSMutableArray array];
for (NSDictionary *d in fetched) {
[events addObject:[ABEvent eventWithDictionary:d]];
}
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.events = events;
events = nil;
});
};
[[ABClient sharedInstance] events:_success failure:nil];
}
上游的:
-(void)events:(ABBlock)success failure:(ABBlock)failure {
NSString *params = [NSString stringWithFormat:@"%@",[ABUser loggedInUser]? [ABUser loggedInUser].name : @"no"];
NSDictionary *dict = @{@"loggedIn": params};
[self get:@"events/live.json" parameters:dict success:success failure:failure];
}
- (void)get:(NSString *)path
parameters:(NSDictionary *)parameters
success:(ABBlock)success
failure:(ABBlock)failure
__block ABBlock blockSuccess = success;
__block ABBlock blockFailure = failure;
NSString *blockPath = path;
NSDictionary *blockParameters = parameters;
AFHTTPSuccessBlock _success = ^(AFHTTPRequestOperation *request, id response) {
if (blockSuccess) {
ABMessage *msg = [ABMessage messageWithObject:response];
dispatch_async(dispatch_get_main_queue(), ^(void) {
blockSuccess(msg);
});
}
};
}
Elsewhere:
typedef void (^ABBlock) (ABMessage *);
barrier_async 块如何使用变量有什么明显错误吗?我想知道是否应该复制作为参数传入的消息 (*m)。