¿Swift admite la reflexión? por ejemplo, ¿hay algo como valueForKeyPath:
y setValue:forKeyPath:
para objetos Swift?
En realidad, ¿tiene siquiera un sistema de tipos dinámico, algo así como obj.class
en Objective-C?
¿Swift admite la reflexión? por ejemplo, ¿hay algo como valueForKeyPath:
y setValue:forKeyPath:
para objetos Swift?
En realidad, ¿tiene siquiera un sistema de tipos dinámico, algo así como obj.class
en Objective-C?
Respuestas:
Parece que está el comienzo de algún apoyo de reflexión:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
De mchambers gist, aquí: https://gist.github.com/mchambers/fb9da554898dae3e54f2
Mirror
realidad, Protocol cita la palabra IDE
varias veces.
_stdlib_getTypeName
puede ayudar.
Si una clase se extiende NSObject
, entonces toda la introspección y el dinamismo de Objective-C funcionan. Esto incluye:
Una deficiencia de esta funcionalidad es la compatibilidad con los tipos de valores opcionales de Swift. Por ejemplo, las propiedades Int se pueden enumerar y modificar, pero Int? las propiedades no pueden. Los tipos opcionales se pueden enumerar parcialmente usando reflect / MirrorType, pero aún no se modifican.
Si una clase no se extiende NSObject
, entonces solo funciona la nueva reflexión muy limitada (¿y en progreso?) (Ver reflect / MirrorType), que agrega una capacidad limitada para preguntar a una instancia sobre su clase y propiedades, pero ninguna de las características adicionales anteriores. .
Cuando no se extiende NSObject, o se usa la directiva '@objc', Swift utiliza de forma predeterminada el envío basado en estática y vtable. Sin embargo, esto es más rápido, en ausencia de una máquina virtual, no permite la interceptación del método en tiempo de ejecución. Esta interceptación es una parte fundamental de Cocoa y es necesaria para los siguientes tipos de características:
Por lo tanto, se recomienda que las clases en aplicaciones Cocoa / CocoaTouch implementadas con Swift:
Resumen:
Datos de referencia: sobrecarga de ejecución para invocaciones de métodos:
(el rendimiento real depende del hardware, pero las proporciones seguirán siendo similares).
Además, el atributo dinámico nos permite instruir explícitamente a Swift de que un método debe usar envío dinámico y, por lo tanto, admitirá la interceptación.
public dynamic func foobar() -> AnyObject {
}
La documentación habla de un sistema de tipos dinámicos, principalmente sobre
Type
y dynamicType
Ver tipo de metatipo (en la referencia del lenguaje)
Ejemplo:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Ahora asumiendo que se TestObject
extiendeNSObject
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
Actualmente, no hay una reflexión implementada.
EDITAR: Aparentemente estaba equivocado, vea la respuesta de stevex. Hay una reflexión simple de solo lectura para las propiedades incorporadas, probablemente para permitir que los IDE inspeccionen el contenido del objeto.
Parece que una API de reflexión Swift no es una alta prioridad para Apple en este momento. Pero además de la respuesta de @stevex, hay otra función en la biblioteca estándar que ayuda.
A partir de la versión beta 6, se _stdlib_getTypeName
obtiene el nombre de tipo alterado de una variable. Pegue esto en un patio de recreo vacío:
import Foundation
class PureSwiftClass {
}
var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"
println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")
La salida es:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
La entrada del blog de Ewan Swick ayuda a descifrar estas cadenas:
por ejemplo, _TtSi
representa el Int
tipo interno de Swift .
Mike Ash tiene una excelente entrada de blog que cubre el mismo tema .
Es posible que desee considerar el uso de toString () en su lugar. Es público y funciona igual que _stdlib_getTypeName () con la diferencia de que también funciona en AnyClass , por ejemplo, en un patio de recreo.
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
Sin reflect
palabra clave en Swift 5, ahora puede usar
struct Person {
var name="name"
var age = 15
}
var me = Person()
var mirror = Mirror(reflecting: me)
for case let (label?, value) in mirror.children {
print (label, value)
}
json
deserialización