与GCD和webView的死锁

180*_*ION 6 webkit objective-c grand-central-dispatch ios

我发现了一个似乎导致WebKit陷入僵局的问题.如果我从我的主线程运行此代码,我正确地看到一个警报.我可以点击警报上的"确定"按钮,它会解散并且一切正常:

[theWebView stringByEvaluatingJavaScriptFromString:@"alert('hi');"];
Run Code Online (Sandbox Code Playgroud)

如果我进行了一些修改,那么警报信息仍会出现,但是无法点击"确定"按钮 - 您无法关闭警报,如果您闯入应用程序,它将挂在stringByEvaluatingJavaScriptFromString通话中:

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

这两者中唯一不同的是,在第二个中,它在调度队列的上下文中在主线程中运行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];
});
Run Code Online (Sandbox Code Playgroud)

有人可以对导致挂起的问题有所了解吗?

编辑:

相关问题:

使用dispatch_async或performSelectorOnMainThread在主线程上执行UI更改?
什么是主队列上的performSelectorOnMainThread和dispatch_async之间的区别?
Grand Central Dispatch(GCD)与performSelector - 需要更好的解释

非常相似的问题:

当使用GCD调用时,UIWebView stringByEvaluatingJavaScriptFromString在iOS5.0/5.1上挂起

ite*_*ian 5

我认为它是在webview中说明的 图片 课堂参考

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

performSelector:withObject:afterDelay:inModes:.默认情况下使用"分别"模式,它NSDefaultRunLoopMode本质上是原子的,而在非原子模式下,dispatch_get_main_queue()您必须更改当前的线程分派模式.

我希望它仍然有用.此外,欢迎提出更多建议.


Joh*_*rug 4

这似乎只是 UIWebView 中的一个错误。根据这个问题,它是在iOS 5中引入的,并且在iOS 4.3及以下版本上没有死锁。

有趣的是,在调用之前呈现 UIAlertView 可以stringByEvaluatingJavaScriptFromString:奇怪地防止死锁:

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');"];
    });
});
Run Code Online (Sandbox Code Playgroud)

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

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


归档时间:

查看次数:

4073 次

最近记录:

11 年,11 月 前