2014-04-05 5 views
7

genannt wird der JSContext von einem UIWebView ich eine Javascript-Funktion erstellt haben, die als Ziel-C-Block implementiert:Aufruf [JSValue callWithArguments:] Schlösser UI wenn alert() Mit

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

Diese Funktion nimmt einen Rückruf als Argument und führt einige Arbeiten in einem NSOperationQueue vor dem Rückruf wie der Aufruf:

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

Dies funktioniert gut, es sei denn, der Rückruf einen Aufruf an alert() enthält:

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

In diesem Fall wird die Warnung angezeigt und die Benutzeroberfläche reagiert nicht mehr. Ich gehe davon aus, dass das Touch-Event zum Schließen des Alarms durch den Alarm blockiert wird.

Wenn ich den Callback ohne den Versand aufrufen (mit anderen Worten, auf dem Thread MyOperation läuft immer) funktioniert es gut, aber ich hatte den Eindruck, dass jeder Code, UI Implikationen haben könnte (mit anderen Worten alle JS-Callbacks) sollten immer im Hauptthread ausgeführt werden. Fehle ich etwas oder ist es wirklich unmöglich, alert() sicher zu verwenden, wenn das JavaScriptCore Framework verwendet wird?

+0

Ich bin nicht sicher, ich verstehe Ihre Frage. Können Sie bitte den vollständigen Code posten, den Sie verklagen, und klar beschreiben, was passiert, was Sie erwartet haben? –

+0

@AbhiBeckert Bearbeitet wie angefordert, um zu machen, wie ich Threads ein wenig klarer handle – erm410

+0

Interessanterweise scheint das Einreihen des Callbacks mit [NSObject performSelectorOnMainThread: withObject: waitUntilDone] nicht den Deadlock zu verursachen, den dispatch_async tut. – erm410

Antwort

9

Nach ein paar Tagen Blick auf Stapel Spuren von Threads warten auf einander, die Lösung war so einfach Ich bin nicht überrascht, dass ich es zugunsten der komplizierteren Sachen zu übersehen.

Wenn Sie asynchron zurück in ein UIWebView ‚s Javascript aufrufen, verwenden window.setTimeout und lassen Sie die JSVirtualMachine darauf achten, den Rückruf von Warteschlangen.

Ersetzen Sie einfach

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

mit

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

Ich finde es schwer zu glauben, aber es funktioniert. WebKit verursacht so viel Trauer. – SergioM