2014-07-06 8 views
7

Ich habe versucht, herauszufinden, wie JavaScriptCore in swift verwenden. Ich stoße auf Probleme, aber wenn ich mit Blöcken als Argumente umgehen muss, scheint der Block sofort ausgeführt zu werden und die Argumente erhalten den Rückgabewert des Blocks. Was mache ich falsch?Schnelle Blöcke funktionieren nicht

Arbeiten Objective-C-Code:

JSContext* context = [[JSContext alloc] initWithVirtualMachine:[[JSVirtualMachine alloc] init]]; 
context[@"test"] = ^(NSString *string) { 
    //code 
}; 

Was ich versucht habe:

1:

var ctx = JSContext(virtualMachine:JSVirtualMachine()) 
var ctx["test"] = {(string:NSString)->() in /*code*/ } 

//Gives me "'JSContext' does not have a member named 'subscript'" 

2:

var ctx = JSContext(virtualMachine:JSVirtualMachine()) 
let n: (string: String)->() = {string in /*code*/} 

ctx.setObject(n, forKeyedSubscript:"test") 

//Gives me "Type '(x: String) ->() does not conform to protocol 'AnyObject'" 

3:

var ctx = JSContext(virtualMachine:JSVirtualMachine()) 
let n: (string: String)->() = {string in /*code*/} 

ctx.setObject(n as AnyObject, forKeyedSubscript:"test") 

//Gives me "Cannot downcast from '(string: String) ->() to [email protected] protocol type 'AnyObject'" 

Fehle ich hier etwas, oder ist das nur ein Fehler in Swift?

Edit:

Ich habe jetzt auch versucht, Vorschläge von Cast closures/blocks

class Block<T> { 
    let f : T 
    init (_ f: T) { self.f = f } 
} 

und dann

ctx.setObject(Block<()->Void> { 
     /*code*/ 
    }, forKeyedSubscript: "test") 

Diese Lösung lässt mich zusammenstellen, aber ich erhalte einen Laufzeitfehler:

Thread 1: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0) 
+0

Scheint das gleiche Problem wie dieses: http://stackoverflow.com/questions/24586293/cast-closures-blocks. –

+0

Es ist ähnlich, aber anders. Bei dieser Frage geht es um Blöcke, die Sie als Rückgabewerte * von * Objc-Methoden erhalten. Hier geht es darum, Swift-Verschlüsse als Blöcke * zu * Objc-Methoden zu übergeben. –

Antwort

26

Es hat etwas damit zu tun, wie Swift den Verschluss umsetzt. Sie müssen @convention(block) verwenden, um zu kommentieren, dass der Abschluss ObjC-Block ist. Verwenden Sie unsafeBitCast zu Guss zwingen sie

var block : @convention(block) (NSString!) -> Void = { 
    (string : NSString!) -> Void in 
    println("test") 
} 

ctx.setObject(unsafeBitCast(block, AnyObject.self), forKeyedSubscript: "test") 

von REPL

swift 
Welcome to Swift! Type :help for assistance. 
    1> import Foundation 
    2> var block : @convention(block)(NSString!) -> Void = {(string : NSString!) -> Void in println("test")} 
block: @convention(block)(NSString!) -> Void = 
    3> var obj: AnyObject = reinterpretCast(block) as AnyObject 
obj: __NSMallocBlock__ = {} // familiar block type 
+0

Das hat wie ein Zauber funktioniert! Ich danke dir sehr. Einzige Sache, scheinbar 'ctx [" test "] =' funktioniert nicht. 'ctx.setObject (obj, forKeyedSubscript:" test ")' tut dies jedoch. Noch einmal, Danke, und hier ist dein Kopfgeld in 22 Stunden, wenn ich kann. – hannesr

+0

Auf Beta6 'reinterpretCast (block) als AnyObject' wurde zu Gunsten von 'unsafeBitCast (block, AnyObject)' veraltet. –

+4

Eigentlich wäre das' unsafeBitCast (block, AnyObject.self) ' –

1

Ich habe eine funktionierende Demo an:

Und hier ist der Teil, der Block implementiert Registrierung:

typealias ID = AnyObject! 
extension JSContext { 
    func fetch(key:NSString)->JSValue { 
     return getJSVinJSC(self, key) 
    } 
    func store(key:NSString, _ val:ID) { 
     setJSVinJSC(self, key, val) 
    } 
    func store(key:NSString, _ blk:()->ID) { 
     setB0JSVinJSC(self, key, blk) 
    } 
    func store(key:NSString, _ blk:(ID)->ID) { 
     setB1JSVinJSC(self, key, blk) 
    } 
    func store(key:NSString, _ blk:(ID,ID)->ID) { 
     setB2JSVinJSC(self, key, blk) 
    } 
} 

Sie benötigen einen sehr kleinen Objc-Code und Bridging-Header, damit es funktioniert. Details finden Sie im Repository.