¿Puedo lanzar un objeto de metaclase a un tipo de protocolo en Swift?
Swift heredó el concepto de metaclase de Objective-C: las clases mismas también se consideran objetos. Una claseFoo
la clase del objeto esFoo.self
y es de tipoFoo.Type
. SiFoo
hereda deBar
, luegoFoo.self
se puede asignar a una variable de tipoBar.Type
, también. Esto tiene al menos dos beneficios:
Estoy particularmente mirando el segundo en este momento. Solo para asegurarme de que todos entiendan lo que busco, aquí hay un ejemplo:
class BaseFoo {
var description: String { return "BaseFoo" }
}
class DerivedFoo: BaseFoo {
override var description: String { return "DerivedFoo" }
}
let fooTypes: [BaseFoo.Type] = [BaseFoo.self, DerivedFoo.self] // metaclass magic!
for type in fooTypes {
let object: BaseFoo = type() // metaclass magic!
println(object)
}
Ahora tengo una serie deAnyClass
objetos (cualquier instancia de metaclase se puede asignar aAnyClass
, al igual que cualquier objeto puede asignarse aAnyObject
), y quiero encontrar cuáles implementan un protocolo dado. El protocolo declararía un inicializador, y yo instanciaría la clase tal como lo hago en el ejemplo anterior. Por ejemplo:
protocol Foo {
init(foo: String)
}
class Bar: Foo {
required init(foo: String) { println("Bar initialized with \(foo)") }
}
class Baz {
required init() { println("I'm not a Foo!") }
}
let types: [AnyClass] = [Bar.self, Baz.self]
Hasta aquí todo bien. Ahora, el problema es determinar si la clase implementa el protocolo. Como las instancias de metaclases son polimórficas, esperaría poder lanzarlas. Sin embargo, aparentemente me falta algo, porque Swift no me deja escribir esto:
for type in types {
if let fooType = type as? Foo.Type {
let obj = fooType(foo: "special snowflake string")
}
}
El error del compilador que obtengo es:
error: 'Foo' no es idéntico a 'AnyObject'
¿Hay alguna forma de determinar si una instancia de metaclase representa una clase que implementa un protocolo, y hay alguna forma de convertir esa instancia en un tipo de protocolo?
Traté de declararFoo
como un protocolo de clase, pero aparentemente no es suficiente.
EDITAR: Acabo de probar con elAny
tipo, y aunque no causa un error de sintaxis, bloquea el compilador Swift.