2014-07-06 13 views
7

Próbowałem dowiedzieć się, jak używać JavaScriptCore w szybkim tempie. Występują jednak problemy, jednak gdy mam do czynienia z blokami jako argumentami, wydaje się, że blok jest uruchamiany natychmiast, a argumenty otrzymują wartość zwracaną bloku. Co ja robię źle?Bloki Swift nie działają

Praca Cel kod C:

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

Co próbowałem:

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'" 

Czy brakuje mi tutaj czegoś, czy to tylko błąd w Swift?

EDIT:

ja teraz też starał sugestie Cast closures/blocks

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

a następnie

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

Rozwiązanie to pozwala mi skompilować, ale pojawia się błąd wykonania:

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

Wydaje się być ten sam problem, co ten: http://stackoverflow.com/questions/24586293/cast-closures-blocks. –

+0

Jest podobny, ale inny. To pytanie dotyczy obsługi bloków, które otrzymujesz jako wartości zwracane * z * metod Objc. Ten dotyczy przechodzenia zamknięć Swift jako bloków * na * metody Objc. –

Odpowiedz

26

Ma to coś wspólnego z zamknięciem narzędzia Swift. Musisz użyć wartości @convention(block), aby opisać, że zamknięcie to blok ObjC. Użyj unsafeBitCast zmusić obsady to

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

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

z 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

To działało jak czar! Dziękuję bardzo. Tylko jedna rzecz, najwyraźniej 'ctx [" test "] =' nie działa. 'ctx.setObject (obj, forKeyedSubscript:" test ")' robi jednak. Jeszcze raz, dziękuję, a tu jest twoja nagroda w 22 godziny, kiedy jestem w stanie. – hannesr

+0

Na Beta6 'reinterpretCast (block) jako AnyObject' został wycofany na rzecz' unsafeBitCast (block, AnyObject) ' –

+4

W rzeczywistości byłby to' unsafeBitCast (block, AnyObject.self) ' –

1

Mam demo działa na:

i tu jest ta część, która realizuje blok rejestracja:

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

Potrzebujesz bardzo małego kodu objc i nagłówka mostu, aby działał. Zobacz szczegóły w repozytorium.