[theWebView stringByEvaluatingJavaScriptFromString:@"alert('hi');"];
如果我进行了一些修改,那么仍然会出现警告消息,但是无法点击“确定”按钮 – 您无法关闭警报,如果您闯入应用程序,它将挂在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,^{ [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
解决方法
有趣的是,在调用stringByEvaluatingJavaScriptFromString之前呈现UIAlertView:奇怪地防止了死锁:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,^{ 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的块才完成.
但它必定是一个bug.奇怪的是,当我首先显示UIAlertView时,不会发生死锁.在这种情况下,iOS可能会在某种队列上放置第二个警报视图,从而防止死锁.奇!