Dies ist eine großartige Frage, und obwohl Chris Lattner diese Funktion absichtlich nicht unterstützen möchte, kann ich, wie viele Entwickler, auch meine Gefühle aus anderen Sprachen nicht loslassen, in denen dies eine triviale Aufgabe ist. Es gibt viele unsafeBitCast
Beispiele, von denen die meisten nicht das vollständige Bild zeigen. Hier ist ein detaillierteres :
typealias SwfBlock = () -> ()
typealias ObjBlock = @convention(block) () -> ()
func testSwfBlock(a: SwfBlock, _ b: SwfBlock) -> String {
let objA = unsafeBitCast(a as ObjBlock, AnyObject.self)
let objB = unsafeBitCast(b as ObjBlock, AnyObject.self)
return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}
func testObjBlock(a: ObjBlock, _ b: ObjBlock) -> String {
let objA = unsafeBitCast(a, AnyObject.self)
let objB = unsafeBitCast(b, AnyObject.self)
return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}
func testAnyBlock(a: Any?, _ b: Any?) -> String {
if !(a is ObjBlock) || !(b is ObjBlock) {
return "a nor b are ObjBlock, they are not equal"
}
let objA = unsafeBitCast(a as! ObjBlock, AnyObject.self)
let objB = unsafeBitCast(b as! ObjBlock, AnyObject.self)
return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}
class Foo
{
lazy var swfBlock: ObjBlock = self.swf
func swf() { print("swf") }
@objc func obj() { print("obj") }
}
let swfBlock: SwfBlock = { print("swf") }
let objBlock: ObjBlock = { print("obj") }
let foo: Foo = Foo()
print(testSwfBlock(swfBlock, swfBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false
print(testSwfBlock(objBlock, objBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false
print(testObjBlock(swfBlock, swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false
print(testObjBlock(objBlock, objBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true
print(testAnyBlock(swfBlock, swfBlock)) // a nor b are ObjBlock, they are not equal
print(testAnyBlock(objBlock, objBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true
print(testObjBlock(foo.swf, foo.swf)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false
print(testSwfBlock(foo.obj, foo.obj)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false
print(testAnyBlock(foo.swf, foo.swf)) // a nor b are ObjBlock, they are not equal
print(testAnyBlock(foo.swfBlock, foo.swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true
Der interessante Teil ist, wie schnell SwfBlock frei in ObjBlock umgewandelt wird, aber in Wirklichkeit haben zwei gegossene SwfBlock-Blöcke immer unterschiedliche Werte, während ObjBlocks dies nicht tun. Wenn wir ObjBlock in SwfBlock umwandeln, passiert ihnen dasselbe, sie werden zu zwei verschiedenen Werten. Um die Referenz zu erhalten, sollte diese Art des Gießens vermieden werden.
Ich verstehe das ganze Thema immer noch, aber eine Sache, die ich mir noch gewünscht habe, ist die Fähigkeit, @convention(block)
Klassen- / Strukturmethoden zu verwenden. Deshalb habe ich eine Feature-Anfrage eingereicht, die eine Abstimmung erfordert oder erklärt, warum dies eine schlechte Idee ist. Ich habe auch das Gefühl, dass dieser Ansatz insgesamt schlecht sein könnte. Wenn ja, kann jemand erklären, warum?
MyClass.self