__destroy_helper_block_上的Objective-C崩溃

Dan*_*erz 25 objective-c ios objective-c-blocks

我有一个都崩溃了像电话iOS应用程序__destroy_helper_block_253,并__destroy_helper_block_278和我真的不知道它应该指向什么后,无论是"destroy_helper_block"被引用或者什么的数量.

有没有人有任何关于如何追踪这些崩溃可能发生的地方的指示?

这是一个示例回溯(请注意,这些行__destroy_helper_block只引用了它包含的文件而没有别的,通常也会包含行号).

Thread : Crashed: com.apple.root.default-priority
0  libdispatch.dylib              0x000000018fe0eb2c _dispatch_semaphore_dispose + 60
1  libdispatch.dylib              0x000000018fe0e928 _dispatch_dispose + 56
2  libdispatch.dylib              0x000000018fe0e928 _dispatch_dispose + 56
3  libdispatch.dylib              0x000000018fe0c10c -[OS_dispatch_object _xref_dispose] + 60
4  Example App                    0x00000001000fe5a4 __destroy_helper_block_278 (TSExampleApp.m)
5  libsystem_blocks.dylib         0x000000018fe53908 _Block_release + 256
6  Example App                    0x00000001000fda18 __destroy_helper_block_253 (TSExampleApp.m)
7  libsystem_blocks.dylib         0x000000018fe53908 _Block_release + 256
8  libdispatch.dylib              0x000000018fe0bfd4 _dispatch_client_callout + 16
9  libdispatch.dylib              0x000000018fe132b8 _dispatch_root_queue_drain + 556
10 libdispatch.dylib              0x000000018fe134fc _dispatch_worker_thread2 + 76
11 libsystem_pthread.dylib        0x000000018ffa16bc _pthread_wqthread + 356
Run Code Online (Sandbox Code Playgroud)

编辑1:这是发生崩溃的文件中定义的一个块的示例(编辑了特定于应用程序的代码).

- (void)doSomethingWithCompletion:(void (^)())completion {
    void (^ExampleBlock)(NSString *) = ^{
        NSNotification *notification = [NSNotification notificationWithName:kExampleNotificationName object:nil userInfo:nil];
        [[NSNotificationCenter defaultCenter] postNotification:notification];

        if (completion) {
            completion();
        }
    };

    // Async network call that calls ExampleBlock on either success or failure below...
}
Run Code Online (Sandbox Code Playgroud)

文件中还有许多其他块,但是大多数块都是作为方法的参数提供的,而不是先被定义然后再引用.

编辑2:为上述功能添加了更多上下文.

Cod*_*aFi 36

堆栈跟踪的每一帧都应该为您提供有关libDispatch正在执行哪些操作以引发崩溃的线索.从底部开始工作:

11 libsystem_pthread.dylib        0x000000018ffa16bc _pthread_wqthread
10 libdispatch.dylib              0x000000018fe134fc _dispatch_worker_thread2 + 76
Run Code Online (Sandbox Code Playgroud)

这两个函数会启动一个工作线程并运行它.在此过程中,它还为线程设置自动释放池.

9  libdispatch.dylib              0x000000018fe132b8 _dispatch_root_queue_drain + 556
Run Code Online (Sandbox Code Playgroud)

此函数表示队列销毁过程的开始.排出特定于线程的自动释放池,并且在该过程中释放该特定队列引用的所有变量.因为这是libDispatch,这意味着底层的mach对象和你提交的工作块必须...

7  libsystem_blocks.dylib         0x000000018fe53908 _Block_release + 256
6  Example App                    0x00000001000fda18 __destroy_helper_block_253 (TSExampleApp.m)
5  libsystem_blocks.dylib         0x000000018fe53908 _Block_release + 25
4  Example App                    0x00000001000fe5a4 __destroy_helper_block_278 (TSExampleApp.m)
Run Code Online (Sandbox Code Playgroud)

这正是这里发生的事情.Number 7是外部块,因为它包含一个要销毁的非平凡对象(还有另一个块),编译器生成了一个析构函数(__destroy_helper_block_253)来摆脱该内部块.应用相同的逻辑线,我们可以推断内部块还有另外一点非常重要的破坏.

3  libdispatch.dylib              0x000000018fe0c10c -[OS_dispatch_object _xref_dispose] + 60
2  libdispatch.dylib              0x000000018fe0e928 _dispatch_dispose + 56
1  libdispatch.dylib              0x000000018fe0e928 _dispatch_dispose + 56
Run Code Online (Sandbox Code Playgroud)

这些线条是你所有麻烦的根本原因.出于某种原因,你已经捕获了你正在回调的队列,或者你已经捕获了一个对象,该对象隐藏了对队列的引用,这样当它走向恐龙的路时,就会占用它的队列.这会导致libDispatch假定队列已完成,并且一直处于dealloc'ing状态,直到达到信号量特定的配置为止

0  libdispatch.dylib              0x000000018fe0eb2c _dispatch_semaphore_dispose + 60
Run Code Online (Sandbox Code Playgroud)

没有信号量释放,马赫会抱怨不要返回KERN_SUCCESS信号量破坏,这是libDispatch中的一个致命错误.事实上,abort()在这种情况下,它将在技​​术上__builtin_trap(),但他们实现相同的目标.因为没有连接调试器,所以你的应用程序就可以了.

所以这提出了一个问题:你如何解决这个问题?好吧,首先你需要找到什么,如果有什么东西引用一个调度对象.你提到你正在做一些异步网络,所以这将是首先检查的地方.如果这些对象中的任何一个恰好拥有一个队列或信号量,或者引用一个对象,并且你没有在任何这些块中强烈捕获它,那么这正是当块与对象一起超出范围时会发生的情况.