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

时间:2013-03-04 03:36:14

标签: ios objective-c grand-central-dispatch nsoperationqueue

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

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

        }
    });    
}

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

以下代码也有错误:

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

        }
    });    
}

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

崩溃是我以前从未见过的类型。这是“EXC _ ???(11)”。奇怪的是,您可以在崩溃后按“继续”按钮,它将继续正常运行。

为什么会崩溃?如何在不导致此行为的情况下将长任务提交到队列?

以下是我迄今为止尝试过的一些事情,它们对这个谜团一无所知:

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

更新#1

该问题仅在LLDB下复制,而非GDB。

2 个答案:

答案 0 :(得分:4)

您无法在主线程上执行冗长的操作。您应该将块发送到另一个线程,然后在块发送结束时返回主线程(如果需要)。

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

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

iOS的容差通常远小于4分钟,但如果你正在调试它会变得更长。模拟器有自己的规则。

启动时,只需几秒钟。但是你不应该在主线程上花费超过一秒的时间做任何事情,然后才会响应直接的用户操作(例如用户点击某些内容)。在主线程上进行工作会导致iOS UI响应速度变慢,生涩而不是玻璃平滑。

如果你的应用程序停止响应OSX上主线程上的事件,那么就会出现问题。你的应用程序停止响应iOS主线程上的事件,iOS看门狗将其取回并拍摄。

来自TechNote 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
        });
    });
};

(我本可以发誓,Apple的文档中有更好的描述,但我现在找不到它。有人吗?)

答案 1 :(得分:2)

来自Apple engineer

  

你看到的“崩溃”并不是真正的崩溃,它是一个日志   应用程序在一段持续的时间内使用过多的CPU时间。它的   存在的理由是告诉你不要那样做,以及CPU时间在哪里   正在度过。在生产中,只需记录日志和您的日志   过程应该继续。但是如果你能避免这些类型的日志,   那会更好。

后来:

  

您应该提交错误报告。 lldb应该足够聪明,默认情况下忽略该陷阱。