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

标签 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) {

        }
    });    
}

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

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

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

以下是我迄今为止尝试过的一些事情,但对这个谜团没有任何启示:
  • 创建我的自己的调度队列 (包括后台线程)
  • 使用 NSBlockOperation 而不是 GCD(仍然崩溃)
  • 插休眠眠。短暂的 sleep (不到 5 秒左右)似乎在 sleep 时延迟了崩溃。更长的 sleep 似乎有更多的作用。所以如果你睡一次五秒钟,它会在 4m 20s 而不是 4m 15s 时崩溃。如果你睡一次 60 秒,大约需要十分钟的时间来崩溃,但它最终会发生。这个线索似乎很重要,但我不知道它可能意味着什么。

  • 更新 #1

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

    最佳答案

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

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

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

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

    启动时,只需几秒钟。但是你不应该在主线程上做任何事情超过一瞬间,然后才能响应直接的用户操作(例如用户点击某物)。在主线程上工作会导致 iOS 用户界面变得 react 迟钝、生涩而不是玻璃般光滑。

    如果您的应用程序停止响应 OSX 上的主线程上的事件,它就会成为沙滩球。您的应用程序停止响应 iOS 上主线程上的事件,iOS 看门狗将其取出并射击。

    来自 TechNote TN2151 :

    The exception code 0x8badf00d indicates that an application has been terminated by iOS because a watchdog timeout occurred. The application took too long to launch, terminate, or respond to system events. One common cause of this is doing synchronous networking on the main thread. Whatever operation is on Thread 0: needs to be moved to a background thread, or processed differently, so that it does not block the main thread.



    一般来说,模式是:
    - (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 的文档中对此有更好的描述,但我现在找不到。有人吗?)

    关于ios - 任何超过 255 秒的任务都会导致 GCD 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15194163/

    相关文章:

    ios - 如何在不更改 iOS 中的图像的情况下删除 imageview 上的绘图?

    ios - 从 DispatchGroup 等待获取最新结果

    android - 在移动设备和桌面设备之间使用表单的最佳方式

    ios - 未找到架构 x86_64 的符号 - iOS

    iOS - cocoapods 不更新

    ios - 有人可以向我解释 initWithNibName 在 iOS 中的用法吗?

    objective-c - 如何在 NSMutableArray 中存储 CGContext 状态?

    swift - 停止在主线程上运行的 DispatchQueue

    ios - 主线程处理问题

    ios - 如何在按钮点击时实现 segue?