introspection swift

introspection - Swift clase introspección y genéricos



(7)

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: Tenga en cuenta que también funciona con protocolos que el objeto puede o no extender

Intento crear dinámicamente un tipo basado en una instancia de clase usando genéricos, sin embargo, encuentro dificultades con la introspección de clases.

Aquí están las preguntas:

  • ¿Hay un Swift equivalente a Obj-C''s self.class ?
  • ¿Hay alguna manera de instanciar una clase usando el resultado NSClassFromString de NSClassFromString ?
  • ¿Hay alguna manera de obtener AnyClass o escribir información estrictamente a partir de un parámetro genérico T ? (Similar a la sintaxis typeof(T) C #)

Aquí hay otro ejemplo que muestra la implementación de la jerarquía de clases, similar a la respuesta aceptada, 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


Aquí se explica cómo usar NSClassFromString . Tienes que saber la superclase de lo que vas a terminar. Aquí hay un par de subclase de superclase 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 @obj especial para dictar el nombre Objective-C munged de estas clases; eso es crucial, porque de lo contrario no conocemos la cadena maldita que designa a cada clase.

Ahora podemos usar NSClassFromString para hacer la clase Zork o la clase Zilk, porque sabemos que podemos escribirlo como un NSObject y no bloquearlo 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.


Bueno, para [NSString class] , el equivalente Swift de [NSString class] es .self (ver documentos de Metatype , 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 rápida intenté ...

class MyClass { } let MyClassRef = MyClass.self // ERROR :( let my_obj = MyClassRef()

Hmm ... el error dice:

La ejecución de Playground falló: error:: 16: 1: error: la construcción de un objeto de clase tipo ''X'' con un valor de meta-tipo requiere un inicializador ''@required''

Y().me() ^ <REPL>:3:7: note: selected implicit initializer with type ''()'' class X { ^

Me tomó un tiempo descubrir lo que esto significa ... 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.


En veloz 3

object.dynamicType

es obsoleto.

En su lugar use:

type(of:object)


Finalmente conseguí algo para trabajar. Es un poco vago, 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.

La desventaja es que tus clases deben derivar de FactoryObject y DEBEN tener el método de inicialización Obj-C + para que tu clase se inserte automágicamente en el mapa de clase mediante la función global "mapClass".


Si estoy leyendo la documentación correctamente, si maneja instancias y, por ejemplo, desea devolver una nueva instancia del mismo tipo que el objeto que se le ha otorgado y el tipo se puede construir con un init (), puede hacer lo siguiente:

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