调用alert()时调用lockingUI

使用UIWebViewJSContext我已经创build了一个作为Objective C块实现的javascript函数:

 JSContext *js = ... //get contect from web view js[@"aFunc"] = ^(JSValue *aString, JSValue *callback) { NSString *realString = [aString toString]; MyOperation *op = [[MyOperation alloc] initWithString:realString andCallback:callback]; //Do some heavy lifting in background [self.myQueue addOperation:op]; } 

这个函数将callback作为参数,并在调用callback之前执行一些NSOperationQueue工作,如:

 - (void)main { JSValue *arg = [self theHeavyWork]; //Now we have finished the heavy work, switch back to main thread to run callback (if any). if ([self.callback isObject] != NO) { dispatch_async(dispatch_get_main_queue(), ^{ [self.callback callWithArguments:@[arg]]; }); } } 

这工作正常,除非callback中包含对alert()的调用:

 //This javascript is part of the page in the UIWebView window.aFunc("important information", function(arg) { alert("Got " + arg); }); 

在这种情况下,警报显示,用户界面变得完全没有响应。 我假设事件触发事件closures警报被阻止的警报在那里。

如果我在没有调度的情况下调用callbackMyOperation (换句话说MyOperation运行在哪个线程上),它的工作原理很好,但是我的印象是,任何可能具有UI含义的代码(换句话说,任何JScallbackMyOperation )都应该总是在主线程上运行。 我错过了什么,或者是否真的不可能在使用JavaScriptCore框架时安全地使用alert()

经过几天,看着彼此等待的堆栈痕迹,解决scheme非常简单,我并不感到惊讶,我忽略了它,而是倾向于尝试更复杂的东西。

如果您想要asynchronous调用UIWebView的JavaScript,请使用window.setTimeout并让JSVirtualMachine负责排队callback。

只要更换

 dispatch_async(dispatch_get_main_queue(), ^{ [self.callback callWithArguments:@[arg]]; }); 

 dispatch_async(dispatch_get_main_queue(), ^{ [self.callback.context[@"setTimeout"] callWithArguments:@[self.callback, @0, arg]]; });