【问题标题】:Deadlock with GCD and webViewGCD 和 webView 的死锁
【发布时间】:2013-10-23 02:28:23
【问题描述】:

我发现了一个似乎导致 WebKit 死锁的问题。如果我从我的主线程运行此代码,我会正确地看到一个警报。我可以点击警报上的“确定”按钮,然后它就会消失,一切正常:

[theWebView stringByEvaluatingJavaScriptFromString:@"alert('hi');"];

如果我稍作修改,警报消息仍然会出现,但无法点击 OK 按钮 - 您无法关闭警报,如果您闯入应用程序,它会挂在 stringByEvaluatingJavaScriptFromString 呼叫中:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_async(dispatch_get_main_queue(), ^{
        [theWebView stringByEvaluatingJavaScriptFromString:@"alert('hi');"];
    });
});

这两者的唯一不同的是,第二个是在调度队列的上下文中在主线程中运行JS。

另一方面,如果我执行以下操作,则不会发生挂起:

- (void) showHi:(id) it
{
    [(UIWebView*)it stringByEvaluatingJavaScriptFromString:@"alert('hi');"];
}

....

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self performSelectorOnMainThread:@selector(showHi:) withObject:theWebView waitUntilDone:NO];
});

有人可以阐明导致挂起的原因吗?

编辑:

相关问题:

Perform UI Changes on main thread using dispatch_async or performSelectorOnMainThread?
Whats the difference between performSelectorOnMainThread and dispatch_async on main queue?
Grand Central Dispatch (GCD) vs. performSelector - need a better explanation

非常相似的问题:

UIWebView stringByEvaluatingJavaScriptFromString hangs on iOS5.0/5.1 when called using GCD

【问题讨论】:

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


    【解决方案1】:

    我认为它在webview类参考中有所说明

    现在,对于您的死锁情况,您可以通过替换它来模拟相同的情况 [self performSelectorOnMainThread:@selector(showHi:) withObject:theWebView waitUntilDone:NO];

    与

    performSelector:withObject:afterDelay:inModes: 。 默认情况下,Respective 模式是 NSDefaultRunLoopMode,它本质上是原子的,而在 dispatch_get_main_queue() 的非原子情况下,您必须更改当前的线程调度模式。

    我希望它仍然提供信息。此外,欢迎提出更多建议。

    【讨论】:

    • 你能详细解释一下运行循环模式,以及dispatch_async 的执行如何导致代码在主线程中运行吗?另外,如何改变线程的调度模式?
    • @itechnician - 我面临同样的问题。错误是 void SendDelegateMessage(NSInvocation *): delegate (webView:identifierForInitialRequest:fromDataSource:) 在等待 10 秒后未能返回。主运行循环模式:kCFRunLoopDefaultMode,它正在阻塞 UI。 WebView 冻结。那么你知道解决这个问题的最佳方法是什么吗?
    【解决方案2】:

    这似乎只是 UIWebView 中的一个错误。根据this question 的说法,它是在 iOS 5 中引入的,在 iOS 4.3 及以下版本没有死锁。

    有趣的是,在调用 stringByEvaluatingJavaScriptFromString: 之前显示 UIAlertView 奇怪地防止了死锁:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            UIAlertView *message = [[UIAlertView alloc] initWithTitle:@"Test"
                                                              message:@"Test"
                                                             delegate:nil
                                                    cancelButtonTitle:@"OK"
                                                    otherButtonTitles:nil];
            [message show];
    
            [theWebView stringByEvaluatingJavaScriptFromString:@"alert('hi');"];
        });
    });
    

    但是,我的理论是:当我在死锁发生后暂停执行时,我看到 WebThread 在__psynch_mutexwait 处停止。由于 JavaScript 引擎在不同的线程上执行,它必须告诉主线程显示警报视图。但是,stringByEvaluatingJavaScriptFromString: 是一个返回值的阻塞调用。只有在通过单击确定解除警报后才能返回该值。这就是死锁似乎发生的地方:从不同的线程我们告诉主线程告诉 web 视图运行 JavaScript(这发生在另一个线程上),这反过来告诉主线程显示一个警报视图,它只能单击 OK 后将其返回值返回给 JavaScript。只有当对stringByEvaluatingJavaScriptFromString: 的调用返回时,我们传递给 GCD 的块才完成。

    不过,这一定是一个错误。奇怪的是,当我首先显示 UIAlertView 时没有发生死锁。在这种情况下,iOS 可能会将第二个警报视图放在某种队列上,从而防止死锁。奇怪!

    【讨论】:

      【解决方案3】:

      有几件事可能是其中的一个因素。正如其他人所提到的,JavaScript 不在主线程上执行,而是在它自己的后台线程上执行。您可能已经注意到代码的执行要等到 JavaScript 完成。我不知道代码中的具体实现,但听起来它在内部使用dispatch_sync 或dispatch_barrier_sync。

      您应该注意的下一项是UIAlertView -show 和 JavaScript alert(..) 提供的警报之间存在显着差异。 UIAlertView -show 异步操作。您可以告诉这一点,因为在解除警报之前调用-show 之后代码继续执行。如果您在 JavaScript 中执行相同的实验,代码执行将停止,直到警报关闭。

      最后,调度队列和线程之间存在区别。你可以在this thread 阅读更多关于它的信息。我怀疑 JavaScript 执行正在执行 [NSThread isMainThread] 并且报告 NO 因为它在主队列上,而不是主线程上。由于此检查报告 NO,因此它会向主队列执行 dispatch_sync,该队列已被阻止等待 JavaScript 队列。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-26
        • 2012-11-08
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 2023-03-27
        • 1970-01-01
        相关资源
        最近更新 更多