与GCD和webView的死锁 [英] Deadlock with GCD and webView

查看:96
本文介绍了与GCD和webView的死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've found an issue that seems to be causing a deadlock in WebKit. If I run this code from my main thread, I rightly see an alert. I can tap on the "OK" button on the alert and it dismisses and all is working well:

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

如果我做了一些修改,那么仍然会出现警告信息,但是无法点按确定按钮on - 你不能忽略警报,如果你闯进应用程序,它会挂在 stringByEvaluatingJavaScriptFromString 调用中:

If I make a slight modification, then the alert message still appears, but the OK button cannot be tapped on - you cannot dismiss the alert and if you break into the app it is hung in the stringByEvaluatingJavaScriptFromString call:

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

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

The only different in these two is that in the second one, it is running the JS in the main thread in the context of a dispatch queue.

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

On the other hand, if I do the following, then the hang does not occur:

- (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];
});

有人能否解决导致挂起的问题?

Can someone shine some light on what is going wrong to cause the hang?

编辑:

相关问题:

使用dispatch_async或performSelectorOnMainThread在主线程上执行UI更改? < br>
performSelectorOnMainThread和主队列上的dispatch_async?

Grand Central Dispatch(GCD)vs. performSelector - 需要更好的解释

非常相似的问题:

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

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

推荐答案

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

This seems to simply be a bug in UIWebView. According to this question, it was introduced in iOS 5 and did not deadlock on iOS 4.3 and below.

有趣的是,在调用 stringByEvaluatingJavaScriptFromString:奇怪地防止了死锁:

Interestingly, presenting a UIAlertView right before the call to stringByEvaluatingJavaScriptFromString: strangely prevents the deadlock:

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(发生在另一个线程上),这反过来告诉主线程显示一个警报视图,它只能单击确定后,将其返回值返回到JavaScript。只有当对 stringByEvaluatingJavaScriptFromString:的调用返回时,我们传递给GCD的块才会完成。

However, my theory is this: When I pause execution after the deadlock occurs, I see that the WebThread is halted at __psynch_mutexwait. Since the JavaScript engine is executed on different threads, it must tell the main thread to display the alert view. However, stringByEvaluatingJavaScriptFromString: is a blocking call that returns a value. The value can only be returned once the alert is dismissed by clicking OK. This is where the deadlock seemingly occurs: From a different thread we tell the main thread to tell the web view to run JavaScript (which happens on yet another thread), which in turn tells the main thread to display an alert view, which can only deliver its return value back to JavaScript once OK is clicked. And only when the call to stringByEvaluatingJavaScriptFromString: returns is the block that we passed to GCD complete.

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

It must be a bug, though. It is strange that the deadlock doesn't occur when I display a UIAlertView first. Maybe iOS puts the second alert view on some kind of queue in that case, which prevents the deadlock. Odd!

这篇关于与GCD和webView的死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆