Clase Swift introspección y genéricos
Estoy tratando de crear dinámicamente un tipo basado en instancia class
usando genéricos, sin embargo estoy encontrando dificultades con la introspección de clase.
Aquí están las preguntas:
- ¿Hay un Swift-equivalente a Obj-C
self.class
? - ¿Hay una manera de instanciar una clase usando el resultado
AnyClass
deNSClassFromString
? - ¿Hay una manera de obtener
AnyClass
o de otra manera escribir información estrictamente a partir de un parámetro genéricoT
? (Similar a la sintaxis de C#typeof(T)
)
7 answers
Bueno, para uno, el equivalente Swift de [NSString class]
es .self
(ver Metatipo docs, aunque son bastante delgados).
De hecho, NSString.class
ni siquiera funciona! Tienes que usar NSString.self
.
let s = NSString.self
var str = s()
str = "asdf"
Del mismo modo, con una clase swift lo intenté...
class MyClass {
}
let MyClassRef = MyClass.self
// ERROR :(
let my_obj = MyClassRef()
Hmm Hmm el error dice: {[14]]}
Playground execution failed: error:: 16: 1: error: construir un objeto de tipo de clase 'X' con un valor metatipo requiere un inicializador '@required'
Y().me() ^ <REPL>:3:7: note: selected implicit initializer with type '()' class X { ^
It me llevó un tiempo averiguar lo que esto significa turns resulta que quiere que la clase tenga un @required init()
class X {
func me() {
println("asdf")
}
required init () {
}
}
let Y = X.self
// prints "asdf"
Y().me()
Algunos de los documentos se refieren a esto como .Type
, pero MyClass.Type
me da un error en el patio de recreo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-04 21:26:39
He aquí cómo usar NSClassFromString
. Tienes que conocer la superclase con la que vas a terminar. Aquí hay un par superclase-subclase que saben cómo describirse a sí mismos para println
:
@objc(Zilk) class Zilk : NSObject {
override var description : String {return "I am a Zilk"}
}
@objc(Zork) class Zork : Zilk {
override var description : String {return "I am a Zork"}
}
Observe el uso de la sintaxis especial @obj
para dictar el nombre munged Objective-C de estas clases; eso es crucial, porque de lo contrario no conocemos la cadena munged que designa a cada clase.
Ahora podemos usar NSClassFromString
para hacer la clase Zork o la clase Zilk, porque sabemos que podemos escribir es como un NSObject y no se bloquea más tarde:
let aClass = NSClassFromString("Zork") as NSObject.Type
let anObject = aClass()
println(anObject) // "I am a Zork"
Y es reversible; println(NSStringFromClass(anObject.dynamicType))
también funciona.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-02 15:11:21
Si estoy leyendo bien la documentación, si trata con instancias y, por ejemplo, desea devolver una nueva instancia del mismo Tipo que el objeto que se le ha dado y el Tipo se puede construir con un init (), puede hacer:
let typeOfObject = aGivenObject.dynamicType
var freshInstance = typeOfObject()
Lo probé rápidamente con String:
let someType = "Fooo".dynamicType
let emptyString = someType()
let threeString = someType("Three")
Que funcionó bien.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-10 00:47:43
In swift 3
object.dynamicType
Está en desuso.
En su lugar use:
type(of:object)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-27 02:33:47
Implementación rápida de tipos de comparación
protocol Decoratable{}
class A:Decoratable{}
class B:Decoratable{}
let object:AnyObject = A()
object.dynamicType is A.Type//true
object.dynamicType is B.Type//false
object.dynamicType is Decoratable.Type//true
NOTA: Observe que también funciona con protocolos que el objeto puede o no extender
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-16 07:34:32
Finalmente tengo algo que trabajar. Es un poco perezoso, pero incluso la ruta NSClassFromString() no funcionó para mí...
import Foundation
var classMap = Dictionary<String, AnyObject>()
func mapClass(name: String, constructor: AnyObject) -> ()
{
classMap[name] = constructor;
}
class Factory
{
class func create(className: String) -> AnyObject?
{
var something : AnyObject?
var template : FactoryObject? = classMap[className] as? FactoryObject
if (template)
{
let somethingElse : FactoryObject = template!.dynamicType()
return somethingElse
}
return nil
}
}
import ObjectiveC
class FactoryObject : NSObject
{
@required init() {}
//...
}
class Foo : FactoryObject
{
class override func initialize()
{
mapClass("LocalData", LocalData())
}
init () { super.init() }
}
var makeFoo : AnyObject? = Factory.create("Foo")
Y bingo, "makeFoo" contiene una instancia de Foo.
El inconveniente es que sus clases deben derrive desde factoryObject y DEBEN tener el método Obj-C +initialize para que su clase se inserte automáticamente en el mapa de clases mediante la función global "mapClass".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-12 20:21:12
Aquí hay otro ejemplo que muestra la implementación de la jerarquía de clases, similar a accepted answer, actualizada para la primera versión de Swift.
class NamedItem : NSObject {
func display() {
println("display")
}
required override init() {
super.init()
println("base")
}
}
class File : NamedItem {
required init() {
super.init()
println("folder")
}
}
class Folder : NamedItem {
required init() {
super.init()
println("file")
}
}
let y = Folder.self
y().display()
let z = File.self
z().display()
Imprime este resultado:
base
file
display
base
folder
display
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-08 21:52:57