使用JSContext
中的UIWebView
我创建了一个实现为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];
}
此函数将回调作为参数,并在调用回调之前在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]];
});
}
}
这样可以正常工作,除非回调包含对alert()
的调用:
//This javascript is part of the page in the UIWebView
window.aFunc("important information", function(arg) { alert("Got " + arg); });
在这种情况下,警报显示并且UI变得完全没有响应。我假设关闭警报的触摸事件正被那里的警报阻止。
如果我在没有调度的情况下调用回调(换句话说就是运行MyOperation
的线程),它的工作正常,但我认为任何可能具有UI含义的代码(在应该始终在主线程上运行任何JS回调。我错过了什么,或者在使用alert()
框架时是否真的无法安全地使用JavaScriptCore
?
答案 0 :(得分:9)
几天后看着线程的堆栈跟踪等待对方,解决方案非常简单我并不感到惊讶,我忽略了它,转而尝试更复杂的东西。
如果您要异步回拨UIWebView
的javascript,请使用window.setTimeout
并让JSVirtualMachine
负责排队回调。
只需替换
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]];
});