ios - ¿Swift apoya la reflexión?
mirror swift (5)
Es posible que desee considerar usar 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 campo de juegos enter
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
¿Swift apoya la reflexión? por ejemplo, ¿hay algo como valueForKeyPath:
y setValue:forKeyPath:
para objetos Swift?
En realidad, ¿tiene incluso un sistema de tipo dinámico, algo así como obj.class
en Objective-C?
La documentación habla sobre un sistema de tipo dinámico, 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 suponiendo que TestObject
amplía NSObject
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.
EDIT: aparentemente estaba equivocado, mira la respuesta de stevex. Hay una simple reflexión de solo lectura para la compilación de propiedades, probablemente para permitir a los IDE inspeccionar el contenido de los objetos.
Parece que hay un comienzo de soporte 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
Parece que una API Swift de reflexión no es una alta prioridad para Apple en este momento. Pero además de @stevex answer hay otra función en la biblioteca estándar que ayuda.
A partir de la versión beta 6, _stdlib_getTypeName
obtiene el nombre de tipo destrozado de una variable. Pega esto en un patio 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))")
El resultado 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
significa tipo interno de Swift.
Mike Ash tiene una gran entrada de blog que cubre el mismo tema .
Si una clase extiende NSObject
, entonces toda la introspección y el dinamismo de Objective-C funcionan. Esto incluye:
- La capacidad de preguntar a una clase sobre sus métodos y propiedades, e invocar métodos o establecer propiedades.
- La capacidad de intercambiar implementaciones de métodos. (agrega funcionalidad a todas las instancias).
- La capacidad de generar y asignar una nueva subclase sobre la marcha. (agrega funcionalidad a una instancia dada)
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 utilizando reflect / MirrorType, pero aún no se modifican.
Si una clase no extiende NSObject
, entonces solo funciona la reflexión nueva, muy limitada (y en curso?) (Vea reflect / MirrorType), que agrega la capacidad limitada de preguntar una instancia sobre su clase y propiedades, pero ninguna de las características adicionales encima.
Cuando no se extiende NSObject, o se usa la directiva ''@objc'', Swift pasa por defecto a despacho estático y basado en vtable. Esto es más rápido, sin embargo, en ausencia de una máquina virtual no permite la interceptación del método de tiempo de ejecución. Esta interceptación es una parte fundamental de Cocoa y es necesaria para los siguientes tipos de funciones:
- Los elegantes observadores de propiedades de Cocoa. (Los observadores de propiedades están integrados en el lenguaje Swift).
- Aplicación no invasiva de preocupaciones transversales como el registro, la gestión de transacciones (es decir, la Programación Orientada a Aspectos).
- Proxies, reenvío de mensajes, etc.
Por lo tanto, se recomienda que las clases en aplicaciones Cocoa / CocoaTouch implementadas con Swift:
- Extiende desde NSObject. El nuevo cuadro de diálogo de clase en Xcode se dirige en esta dirección.
- Cuando la sobrecarga de un envío dinámico conduce a problemas de rendimiento, entonces se puede usar el envío estático, en bucles estrechos con llamadas a métodos con cuerpos muy pequeños, por ejemplo.
Resumen:
- Swift puede comportarse como C ++, con un rápido envío estático / vtable y una reflexión limitada. Esto lo hace adecuado para aplicaciones de bajo nivel o alto rendimiento, pero sin la complejidad, la curva de aprendizaje o el riesgo de error asociado con C ++.
- Si bien Swift es un lenguaje compilado, el estilo de mensajería de la invocación de métodos agrega la introspección y el dinamismo que se encuentran en los lenguajes modernos como Ruby y Python, al igual que Objective-C, pero sin la sintaxis heredada de Objective-C.
Datos de referencia: tara de ejecución para invocaciones de métodos:
- estático: <1.1ns
- vtable: ~ 1.1ns
- dinámico: ~ 4.9ns
(el rendimiento real depende del hardware, pero las proporciones se mantendrán similares).
Además, el atributo dinámico nos permite indicar explícitamente a Swift que un método debe usar despacho dinámico y, por lo tanto, admitirá la intercepción.
public dynamic func foobar() -> AnyObject {
}