dispatch_semaphore_dispose上的EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 0x0)

Boo*_*oon 40 exception objective-c grand-central-dispatch ios

我在dispatch_semaphore_dispose上获得了EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 0x0),但实际上并不知道如何找到它的根本原因.我的代码使用dispatch_async,dispatch_group_enter等.

更新:崩溃的原因是由于webserviceCall(请参阅下面的代码)从不调用onCompletion,并且当代码再次运行时,我收到错误EXC_BAD_INSTRUCTION.我确认情况确实如此,但不确定为什么或如何防止这种情况.

在此输入图像描述

码:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();

     for (...) {
        if (...) {
            dispatch_group_enter(group);
            dispatch_async(queue, ^{

               [self webserviceCall:url onCompletion:^{
                     dispatch_group_leave(group);
               }];
            });
        }
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)));
    dispatch_sync(queue, ^{
        // call completion handler passed in by caller
    });
});
Run Code Online (Sandbox Code Playgroud)

332*_*329 42

从堆栈跟踪中EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)发生,因为dispatch_group_t它在仍然锁定(等待dispatch_group_leave)时被释放.

根据你的发现,这就是发生的事情:

  • dispatch_group_t group创建了.group保留计数= 1.
  • -[self webservice:onCompletion:]抓住了group.group保留计数= 2.
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... });又抓住了group.group保留计数= 3.
  • 退出当前范围.group被释放了.group保留计数= 2.
  • dispatch_group_leave 从未被称为.
  • dispatch_group_wait超时了 该dispatch_async区块已完成.group被释放了.group保留计数= 1.
  • 你再次调用了这个方法.当-[self webservice:onCompletion:]再次调用时,旧onCompletion块被替换为新块.所以,老人group被释放了.group保留计数= 0. group被解除分配.这导致了EXC_BAD_INSTRUCTION.

要解决这个问题,我建议你应该找出为什么-[self webservice:onCompletion:]没有调用onCompletion阻塞,并修复它.然后确保在上一次调用完成后,将对该方法进行下一次调用.


如果您允许多次调用该方法,无论先前的调用是否完成,您可能会找到group适合您的人:

  • 您可以将超时从2秒更改DISPATCH_TIME_FOREVER为合理的时间,以便所有人都-[self webservice:onCompletion]应该onCompletion按时间调用其块.因此,块dispatch_async(...)将为您保留它.
    要么
  • 您可以添加group到集合中,例如NSMutableArray.

我认为这是为此操作创建专用类的最佳方法.当你想调用webservice时,你就创建了一个类的对象,调用它上面的方法,并将完成块传递给它,它将释放该对象.在课堂上,有一个dispatch_group_t或以下的ivar dispatch_semaphore_t.

  • 哇,惊人的分析.如果我将组添加到集合中,它将永远不会被释放,对吧?我可能无法修复非返回的webservice,因为这是一个框架,我无法阻止其他人创建不返回(错误地)的webservice调用,我想确保我的框架不会崩溃那些情况. (2认同)

Mru*_*ank 7

我的问题已经解决,IBOutlet但未与界面构建器连接并在swift文件中使用.


pka*_*amb 6

我有一个不同的问题让我想到了这个问题,这个问题可能比接受的答案中的过度发布问题更常见.

根本原因是我们的完成块由于网络处理程序中的错误if/else掉落而被调用两次,导致dispatch_group_leave每次调用两次调用dispatch_group_enter.

多次调用完成块:

dispatch_group_enter(group);
[self badMethodThatCallsMULTIPLECompletions:^(NSString *completion) {

    // this block is called multiple times
    // one `enter` but multiple `leave`

    dispatch_group_leave(group);
}];
Run Code Online (Sandbox Code Playgroud)

通过dispatch_group进行调试 count

EXC_BAD_INSTRUCTION,您应该仍然可以访问调试器中的dispatch_group.打印出dispatch_group,你会看到:

<OS_dispatch_group: group[0x60800008bf40] = { xrefcnt = 0x2, refcnt = 0x1, port = 0x0, count = -1, waiters = 0 }>

当你看到count = -1它表明你已经超越了dispatch_group.一定要dispatch_enterdispatch_leave小组成对配对.


Gab*_*iel 5

有时,获取 aEXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)所需要的只是缺少一个return语句。

这当然是我的情况。