【问题标题】:EXC_BAD_ACCESS in nested dispatch_async with an NSAutoreleasePool带有 NSAutoreleasePool 的嵌套 dispatch_async 中的 EXC_BAD_ACCESS
【发布时间】:2012-01-20 17:35:31
【问题描述】:

我有一些类似于以下代码的代码:

dispatch_queue_t queue          = dispatch_queue_create("", 0);
dispatch_queue_t inner_queue    = dispatch_queue_create("", 0);
dispatch_async(queue,
^{
    NSAutoreleasePool* autoreleasePool = [[NSAutoreleasePool alloc] init];
    NSArray* objects = [self.otherObject getObjectsFromSlowQuery];

    [objects enumerateObjectsWithUsingBlock:^(id anObject, NSUInteger idx, BOOL *stop) 
    {
        [anObject prepare];
        dispatch_async(inner_queue,
        ^{
            InnerObject* innerObject = anObject.innerObject;
            [self.helper doSomethingExpensiveWithObject:innerObject];
        });
        dispatch_sync(self.syncQueue,
        ^{
             [self insertIntoCollection:anObject];
        });
    }];
    dispatch_release(inner_queue);
    [autoreleasePool drain];
});
dispatch_release(queue);

其中[anObject.innerObject]nonatomic 属性。

当我尝试在doSomethingExpensiveWithObject: 调用中访问innerObject 的属性时,我收到了来自用户的崩溃报告,其中显示objc_msgSend() 中的EXC_BAD_ACCESS

起初我在想autoreleasePool 可能已经耗尽,所以innerObject 实例在从doSomethingExpensiveWithObject: 返回之前被释放,但据我所知anObject 应该由内部dispatch_async 调用保留还应该保持innerObject 活着。

我错过了什么?

【问题讨论】:

  • 代码在没有队列的情况下可以工作吗?另外,你don't need to allocate an NSAutoreleasePool在这里。
  • 块不会影响它们捕获的对象的保留计数。
  • @user1139069: They do. 这就是为什么需要__block 来关闭它(并使块能够修改变量)。
  • @user1139069 dispatch_async 调用 Block_copy 将变量保留在块范围内。
  • 没有特别证据表明自动释放池与崩溃有关。但是使用dispatch_async 意味着该块可能在具有自己的自动释放池的其他线程上运行(在每个块运行后可能不会被耗尽)。因此,如果您认为 doSomethingExpensiveWithObject: 需要它,您应该在 inner_queue 块内创建/排出一个池。

标签: objective-c exc-bad-access grand-central-dispatch nsautoreleasepool


【解决方案1】:

仪器可以快速解决这个问题 - 与僵尸一起运行并在它停止时查看引用计数。

【讨论】:

  • 我无法重现这个错误,所以现在运行带有僵尸的仪器没有帮助。
猜你喜欢
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多