2016-06-19 14 views
5

Ich schreibe eine iOS-App (mit Xcode 7.3 und Swift 2.2) mit JavascriptCode-Framework. JavaScript-Methoden aus Swift-Funktionen aufrufen perfekt, aber wenn ich die schnelle Methode von Javascript aufrufen, zeigt xcode einfach eine "Laden" Art von Symbol und nichts passiert. Ich muss xcode "erzwingen", um aus diesem Zustand herauszukommen. Ich habe https://www.raywenderlich.com/124075/javascriptcore-tutorial und http://nshipster.com/javascriptcore/ gefolgt und ich versuche ziemlich einfache Anrufe.Aufruf von swift-Methode von JavaScript hängt xcode und Anwendung

Hat jemand diese Art von Problem konfrontiert?

Mein SWIFT-Code ist wie folgt:

@objc protocol WindowJSExports : JSExport { 
    var name: String { get set } 
    func getName() -> String 
    static func createWindowWithName(name: String) -> WindowJS 
} 

@objc class WindowJS : NSObject, WindowJSExports { 
    dynamic var name: String 
    init(name: String) { 
     self.name = name 
    }  
    class func createWindowWithName(name: String) -> WindowJS { 
     return WindowJS(name: name) 
    }  
    func getName() -> String { 
     NSLog("getName called from JS context") 
     return "\(name)" 
    } 
} 

ich den Kontext am Initialisierung wie folgt:

runContext = JSContext() 
runContext.name = "test_Context" 

windowToJs = WindowJS(name: "test") 
runContext.setObject(windowToJs.self, forKeyedSubscript: "WindowJS") 

Wenn ich die letzten beiden Zeilen in obigen Code mit folgenden Code ohne Instanziierung ersetzen, Der Code wird einfach nicht geladen.

runContext.setObject(WindowJS.self, forKeyedSubscript: "WindowJS") 

Und der Javascript-Code ist so einfach wie

function check() { 
    return WindowJS.getName() 
} 

ich der Haltepunkt in der Prüfung JS Funktion schlagen sehen Sie sind und wenn die WindowJS.getName aufgerufen wird, Xcode wird einfach nicht mehr reagiert.

+0

Wie wird der JavaScript-Aufruf ausgelöst? Wird es zufällig ausgelöst, indem es (auch als Nebeneffekt) von Swift genannt wird? ZB ist es möglich, dass Sie mit einem Swift-> JS-> Swift-Zyklus enden? – DarkDust

+0

@DarkDust Danke! Das ist was passiert. Wie erreiche ich einen asynchronen Effekt wie den von "postMessage in JavaScript in WKWebView" in einem JSContext? – Amruta

Antwort

2

Sie erstellen einen Deadlock, da Sie von Swift zu JavaScript zurück zu Swift aufrufen. Ich bin mir nicht sicher, warum genau das ein Deadlock ist, aber ich hatte kürzlich ein ähnliches Problem mit WKWebView auf dem Mac.

Sie müssen dies entkoppeln und die Kommunikation asynchron machen. Dies bedeutet natürlich, dass Sie in diesem Fall nicht einfach einen Wert aus Ihrer JS-Funktion zurückgeben können.

zu entkoppeln, können Sie aus der Sackgasse durch die Arbeit der JavaScript-Funktion aus dem aktuellen Runloop setTimeout zu tun Iteration benötigt aufzuschieben:

function myFunction() { 
    setTimeout(function() { 
    // The actual work is done here. 
    // Call the Swift part here. 
    }, 0); 
} 

Die ganze nativer ↔︎ JavaScript Kommunikation ist sehr, sehr schwierig . Vermeide es, wenn du kannst. Es gibt ein Projekt namens XWebView, das Ihnen helfen kann, wenn es darum geht, die Überbrückung zwischen den beiden Welten zu erleichtern.

+0

Danke! Ich bekomme einen Fehler für setTimeout. Müssen Sie etwas Besonderes tun, damit setTimeout (/ * someCode * /, 0) funktioniert? Ich brauche das auch. – Amruta

+0

Sie müssen eine Funktion übergeben. Durchsuchen Sie das Web, es gibt Tonnen von Beispielen, wie man es benutzt. – DarkDust

1

Die setTimeout könnte durch Hinzufügen von folgenden Code zu meiner schnellen Funktion gelöst werden.

let setTimeout: @convention(block) (JSValue, Int) ->() = 
{ callback, timeout in 
    let timeVal = Int64(timeout) 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeVal), dispatch_get_main_queue(), { callback.callWithArguments(nil)}) 
} 

Um diesen nativen Code dem JS-Kontext zugänglich zu machen, habe ich auch folgende hinzugefügt.

runContext.setObject(unsafeBitCast(setTimeout, AnyObject.self), forKeyedSubscript: "setTimeout") 

Die Dinge funktionierten dann gut.