2014-04-05 13 views
7

Utilizzando la JSContext da un UIWebView ho creato una funzione JavaScript che viene implementato come un blocco C Obiettivo:Calling [callWithArguments JSValue:] serrature UI quando alert() viene chiamato

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

Questa funzione richiede un callback come argomento e svolge un lavoro in un NSOperationQueue prima di chiamare la callback come:

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

Questo funziona bene, a meno che il callback contiene una chiamata a alert():

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

In questo caso, l'avviso viene visualizzato e l'interfaccia utente non risponde più. Suppongo che l'evento che l'evento di tocco per chiudere l'avviso sia bloccato dall'avviso che si trova lì.

Se chiamo il callback senza la spedizione (in altre parole su cui si inserisce sempre lo MyOperation) funziona perfettamente, ma ho avuto l'impressione che qualsiasi codice che potrebbe avere implicazioni dell'interfaccia utente (in altre parole qualsiasi Callback JS) dovrebbe sempre essere eseguito sul thread principale. Mi manca qualcosa o è davvero impossibile usare in modo sicuro alert() quando si utilizza il framework JavaScriptCore?

+0

io non sono sicuro di aver capito la tua domanda. Puoi pubblicare per favore il codice completo che stai citando e descrivere chiaramente cosa succede contro ciò che ti aspettavi che accadesse? –

+0

@AbhiBeckert Modificato come richiesto per rendere un po 'più chiaro il modo in cui gestisco i thread – erm410

+0

È interessante notare che l'accodamento del callback utilizzando [NSObject performSelectorOnMainThread: withObject: waitUntilDone] non sembra causare il deadlock eseguito da dispatch_async. – erm410

risposta

9

Dopo un paio di giorni che guardavano le tracce di fili in attesa l'uno dell'altro, la soluzione era così semplice che non sono sorpreso di averlo trascurato in favore di provare cose più complicate.

Se si vuole richiamare in javascript 's un UIWebView in modo asincrono, utilizzare window.setTimeout e lasciare che il JSVirtualMachine prendersi cura di accodamento callback.

basta sostituire

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

Lo trovo difficile da credere ma funziona. WebKit sta causando così tanto dolore. – SergioM

Problemi correlati