2016-06-19 40 views
5

Sto scrivendo un'app per iOS (utilizzando xcode 7.3 e swift 2.2) utilizzando il framework JavascriptCode. Chiamare i metodi javascript da swift funziona perfettamente, ma quando chiamo il metodo swift da javascript, xcode mostra semplicemente un tipo di "caricamento" di simbolo e non succede nulla. Ho bisogno di "forzare l'uscita" xcode per uscire da questo stato. Ho seguito https://www.raywenderlich.com/124075/javascriptcore-tutorial e http://nshipster.com/javascriptcore/ e sto provando le chiamate abbastanza semplici.Chiamata al metodo rapido da JavaScript si blocca xcode e applicazione

Qualcuno ha affrontato questo tipo di problema?

Il mio codice swift è il seguente:

@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)" 
    } 
} 

sto inizializzazione del contesto come segue:

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

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

Se sostituisco le ultime due righe di codice precedente con sottostante codice senza creare un'istanza di esso, il codice semplicemente non riesce a caricare.

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

E il codice JavaScript è semplice come

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

Io vedo il punto di interruzione viene colpito al controllo funzionale JS e quando il WindowJS.getName viene chiamato, Xcode diventa semplicemente non risponde.

+0

Come viene attivata la chiamata JavaScript? È per caso innescato chiamandolo (anche come effetto collaterale) da Swift? Ad esempio, è possibile che tu finisca con un ciclo Swift-> JS-> Swift? – DarkDust

+0

@DarkDust Grazie! Questo è ciò che sta accadendo. Come posso ottenere un effetto asincrono come quello di "postMessage in JavaScript in WKWebView" in un JSContext? – Amruta

risposta

2

Stai creando un deadlock poiché stai chiamando da Swift a JavaScript di nuovo a Swift. Non sono sicuro del perché si tratti di un deadlock ma di recente ho riscontrato un problema simile con WKWebView su Mac.

È necessario disaccoppiare questo e rendere la comunicazione asincrona. Questo ovviamente significa che non puoi semplicemente restituire un valore dalla tua funzione JS in questo caso.

Per il disaccoppiamento, è possibile sbloccare la situazione, rinviando il lavoro la funzione JavaScript deve fare fuori dal runloop corrente di iterazione con setTimeout:

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

L'intero ↔︎ comunicazione nativo JavaScript è molto, molto difficile . Evitalo se puoi. C'è un progetto chiamato XWebView che potrebbe essere in grado di aiutarti mentre cerca di facilitare il collegamento tra i due mondi.

+0

Grazie! Ottengo un errore per setTimeout. Hai bisogno di fare qualcosa di speciale per setTimeout (/ * someCode * /, 0) per funzionare? Ne ho bisogno anch'io. – Amruta

+0

È necessario passare una funzione. Cerca nel web, ci sono un sacco di esempi su come usarlo. – DarkDust

1

Il setTimeout può essere risolto aggiungendo la seguente parte di codice alla mia funzione rapida.

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)}) 
} 

Per esporre questo codice nativo al contesto JS, ho aggiunto anche seguente.

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

Le cose poi hanno funzionato bene.