任何超过 255 秒的任务 GCD 都会崩溃

Dre*_*rew 1 objective-c nsoperationqueue grand-central-dispatch ios

以下代码会在 iOS 模拟器中产生崩溃。

- (void)viewDidLoad
{
    [super viewDidLoad];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDate *sleepStart = [NSDate date];
        while ([sleepStart timeIntervalSinceNow] > -300) {

        }
    });    
}
Run Code Online (Sandbox Code Playgroud)

更新:即使在后台线程上也会出现此问题

下面的代码也有错误:

- (void)viewDidLoad
{
    [super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSDate *sleepStart = [NSDate date];
        while ([sleepStart timeIntervalSinceNow] > -300) {

        }
    });    
}
Run Code Online (Sandbox Code Playgroud)

就这样。将其粘贴到任何视图控制器中,在模拟器中运行该应用程序正好 4 分 15 秒,它就会崩溃。

这种崩溃是我以前从未见过的。是“EXC_???(11)”。奇怪的是,您可以在崩溃后按“继续”按钮,它会像平常一样继续。

为什么会崩溃?如何将长任务提交到队列而不导致此行为?

到目前为止,我尝试过以下一些方法,但还没有解开这个谜团:

  • 创建我自己的调度队列(包括后台线程上的调度队列)
  • 使用 NSBlockOperation 而不是 GCD (仍然崩溃)
  • 插入睡眠。短暂的睡眠(少于 5 秒左右)似乎会延迟睡眠时间的崩溃。睡眠时间越长似乎作用越多。所以如果你睡眠一次五秒,它会在 4m 20s 而不是 4m 15s 时崩溃。如果你睡眠一次持续 60 秒,大约需要十分钟才会崩溃,但它最终会发生。这条线索似乎很重要,但我不知道它意味着什么。

更新#1

该问题仅在 LLDB 下重现,在 GDB 下不重现。

Ste*_*her 5

您不能在主线程上执行冗长的操作。您应该将块分派到另一个线程,然后在块结束时分派回主线程(如果需要)。

使用dispatch_async(dispatch_get_main_queue(),^{});会导致您的操作在不久的将来在主线程上执行(阻塞)。

主线程受定时器保护;如果你停止响应事件,iOS 将杀死它。这是故意的:不要在主线程上做繁重的工作!

iOS 的容忍度通常远小于四分钟,但如果您进行调试,它会变得更长。模拟器有它自己的规则。

启动时,只需几秒钟的时间。但是,您不应该在主线程上执行任何花费超过一瞬间的操作,并且只能在响应直接用户操作(例如用户点击某些内容)时执行。在主线程上工作会导致 iOS UI 响应速度变慢,变得不稳定,而不是光滑。

如果您的应用程序停止响应 OSX 上主线程上的事件,它就会陷入困境。你的应用程序停止响应 iOS 主线程上的事件,iOS 看门狗将其取出并射击它。

来自技术说明 TN2151

异常代码 0x8badf00d 表示应用程序因发生看门狗超时而被 iOS 终止。应用程序启动、终止或响应系统事件的时间过长。造成这种情况的一个常见原因是在主线程上进行同步网络。无论线程 0 上有什么操作:都需要移至后台线程,或以不同的方式处理,这样就不会阻塞主线程。

一般来说,模式是:

- (IBAction)tappedWhatever:(id)sender {
    // visually start operation
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
        // do work here, off main thread
        // (you can't update the UI here)
        dispatch_async(dispatch_get_main_queue(),^{
            // show progress in UI
        });
        // more heavy lifting
        dispatch_async(dispatch_get_main_queue(),^{
            // update UI to show operation complete and move to next step
        });
    });
};
Run Code Online (Sandbox Code Playgroud)

(我可以发誓苹果文档中有对此的更好描述,但我现在找不到。有人吗?)