Llamar a bloquea la interfaz de usuario cuando se llama a alert ()

Usando el JSContext desde un UIWebView , he creado una function javascript que se implementa como un bloque Objective C:

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

Esta function toma una callback como argumento y realiza algún trabajo en un NSOperationQueue antes de llamar a la callback como:

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

Esto funciona bien, a less que la callback contenga una llamada para alert() :

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

En este caso, se muestra la alerta y la interfaz de usuario se vuelve completamente indiferente. Asumo que el evento de toque para cerrar la alerta está siendo bloqueado por la alerta que está allí.

Si llamo a la callback sin el envío (en otras palabras, en el que nunca se ejecuta MyOperation ) funciona perfectamente, pero tenía la printing de que cualquier código que pudiera tener implicaciones de UI (en otras palabras, cualquier callback de JS) debería siempre se ejecuta en el hilo principal. ¿Me estoy perdiendo algo, o hago es realmente imposible usar alert() manera segura cuando uso el marco JavaScriptCore ?

Después de un par de días mirando los trazos de stack de hilos esperando el uno al otro, la solución fue tan simple que no me sorprende que lo haya pasado por alto en favor de probar cosas más complicadas.

Si desea volver a llamar de forma asíncrona a un javascript de UIWebView , use window.setTimeout y deje que JSVirtualMachine se encargue de JSVirtualMachine queue la callback.

Solo reemplaza

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

con

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