GCD与超过255秒的任何任务崩溃
以下代码在iOS模拟器中产生崩溃。GCD与超过255秒的任何任务崩溃
- (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下再现。
的“崩溃”你看到的是不是真的崩溃,其日志时 应用程序使用太多CPU时间持续一段时间。它的 存在的理由是告诉你不要这样做,并且CPU时间 正在花费。在生产中,日志会被简单地记录下来,并且您的过程应该继续。但是如果你能避免这些类型的日志,那就更好了。
及更高版本:
您应该提交错误报告。 lldb应该足够聪明以默认忽略该陷阱。
您不能在主线程上执行冗长的操作。您应该将块分派给另一个线程,然后在块的末尾派送回主线程(如果需要的话)。
使用dispatch_async(dispatch_get_main_queue(),^{});
会导致您的操作在不久的将来在主线程上执行(阻塞)。
主线程受计时器保护;如果你停止响应事件,iOS会终止它。这是故意的:不要在主线上举重!
iOS的容忍度通常是,远远低于4分钟的,但如果您正在调试,它会变得更长。模拟器有其自己的规则。
在启动时,这只是几秒钟的事情。但是你不应该在主线程上花费不止一秒的时间,而只是在直接用户操作(例如用户点击某件事)时做出响应。在主线程上工作会导致iOS界面变得不太灵敏,而不是平滑。
如果您的应用程序停止响应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
});
});
};
(?我可以发誓,有这个苹果的文档更好的说明,但现在我找不到它的任何人)
你举起了主线?是的,它会崩溃。 – 2013-03-04 03:38:23
为了扩大这个范围:iOS发现你的应用一直没有响应(对任何事件没有响应)时间过长,并且因为这意味着你的应用被破坏,它会杀死你的应用。你不应该超过1/60秒,更不用说4分钟了。为什么不在一个并发队列中运行此块? – 2013-03-04 03:42:59
问题更新后,行为与主队列是否被阻止或后台队列无关。 – Drew 2013-03-04 05:29:28