Esta es una gran pregunta y aunque Chris Lattner intencionalmente no quiere admitir esta característica, yo, como muchos desarrolladores, tampoco puedo dejar de lado mis sentimientos provenientes de otros lenguajes donde esta es una tarea trivial. Hay muchos unsafeBitCast
ejemplos, la mayoría de ellos no muestran la imagen completa, aquí hay uno más detallado :
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))
print(testSwfBlock(objBlock, objBlock))
print(testObjBlock(swfBlock, swfBlock))
print(testObjBlock(objBlock, objBlock))
print(testAnyBlock(swfBlock, swfBlock))
print(testAnyBlock(objBlock, objBlock))
print(testObjBlock(foo.swf, foo.swf))
print(testSwfBlock(foo.obj, foo.obj))
print(testAnyBlock(foo.swf, foo.swf))
print(testAnyBlock(foo.swfBlock, foo.swfBlock))
La parte interesante es cómo Swift lanza libremente SwfBlock a ObjBlock, pero en realidad dos bloques SwfBlock emitidos siempre tendrán valores diferentes, mientras que ObjBlocks no. Cuando lanzamos ObjBlock a SwfBlock, les sucede lo mismo, se convierten en dos valores diferentes. Entonces, para preservar la referencia, este tipo de casting debe evitarse.
Todavía estoy comprendiendo todo este tema, pero una cosa que dejé deseando es la capacidad de usar @convention(block)
en métodos de clase / estructura, así que presenté una solicitud de función que necesita una votación positiva o explicar por qué es una mala idea. También tengo la sensación de que este enfoque podría ser malo en conjunto, si es así, ¿alguien puede explicar por qué?
MyClass.self
)