以下代码会在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)”。奇怪的是,您可以在崩溃后按“继续”按钮,它将继续正常运行。
为什么会崩溃?如何在不导致此行为的情况下将长任务提交到队列?
以下是我迄今为止尝试过的一些事情,它们对这个谜团一无所知:
更新#1
该问题仅在LLDB下复制,而非GDB。
答案 0 :(得分:4)
您无法在主线程上执行冗长的操作。您应该将块发送到另一个线程,然后在块发送结束时返回主线程(如果需要)。
使用dispatch_async(dispatch_get_main_queue(),^{});
会导致您的操作在不久的将来在主线程上执行(阻塞)。
主线程由计时器保护;如果你停止响应事件,iOS将杀死它。这是故意的:不要在主线上做重物!
iOS的容差通常远小于4分钟,但如果你正在调试它会变得更长。模拟器有自己的规则。
启动时,只需几秒钟。但是你不应该在主线程上花费超过一秒的时间做任何事情,然后才会响应直接的用户操作(例如用户点击某些内容)。在主线程上进行工作会导致iOS UI响应速度变慢,生涩而不是玻璃平滑。
如果你的应用程序停止响应OSX上主线程上的事件,那么就会出现问题。你的应用程序停止响应iOS主线程上的事件,iOS看门狗将其取回并拍摄。
异常代码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)
你看到的“崩溃”并不是真正的崩溃,它是一个日志 应用程序在一段持续的时间内使用过多的CPU时间。它的 存在的理由是告诉你不要那样做,以及CPU时间在哪里 正在度过。在生产中,只需记录日志和您的日志 过程应该继续。但是如果你能避免这些类型的日志, 那会更好。
后来:
您应该提交错误报告。 lldb应该足够聪明,默认情况下忽略该陷阱。