ios reflection swift

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 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 { }