Est-ce que Swift supporte la réflexion? Par exemple, y a-t-il quelque chose comme valueForKeyPath:
et setValue:forKeyPath:
pour Swift?
A-t-il même un système de type dynamique, quelque chose comme obj.class
en Objective-C?
On dirait qu'il y a un début de support de réflexion:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
De mchambers Gist, ici: https://Gist.github.com/mchambers/fb9da554898dae3e54f2
Si une classe étend NSObject
, alors toute l'introspection et le dynamisme d'Objective-C fonctionnent. Ceci comprend:
L'un des inconvénients de cette fonctionnalité est la prise en charge des types de valeur facultatifs Swift. Par exemple, les propriétés Int peuvent être énumérées et modifiées, mais pas les propriétés Int?. Les types facultatifs peuvent être énumérés partiellement à l'aide de reflect/MirrorType, mais tout de même non modifié.
Si une classe ne s'étend pas NSObject
, alors seule la nouvelle réflexion très limitée (et en cours?) Fonctionne (voir reflect/MirrorType), ce qui ajoute une capacité limitée à interroger une instance sur sa classe et ses propriétés, mais aucune des fonctionnalités supplémentaires ci-dessus.
Lorsque vous n’étendez pas NSObject ou n’utilisez pas la directive '@objc', Swift est réglé par défaut sur la répartition statique et basée sur vtable. Ceci est plus rapide, mais en l’absence de machine virtuelle ne permet pas Interception de méthode d'exécution. Cette interception est un élément fondamental de Cocoa et est requise pour les types de fonctionnalités suivants:
Par conséquent, il est recommandé que les applications Cocoa/CocoaTouch implémentées avec Swift:
Résumé:
Données de référence: temps système d'exécution pour les appels de méthode:
(Les performances réelles dépendent du matériel, mais les ratios resteront similaires).
En outre, l’attribut dynamique nous permet d’indiquer explicitement à Swift) qu’une méthode doit utiliser la répartition dynamique et prend donc en charge l’interception.
public dynamic func foobar() -> AnyObject {
}
La documentation parle d’un système de types dynamique, principalement de
Type
et dynamicType
Voir Type de métatype (dans la référence du langage)
Exemple:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Supposons maintenant que TestObject
s'étend NSObject
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
Actuellement, aucune réflexion n'est mise en place.
MODIFIER: J'avais apparemment tort, voir la réponse de stevex. Il existe une simple réflexion en lecture seule pour les propriétés intégrées, probablement pour permettre aux IDE d’inspecter le contenu des objets.
Il semble qu'une API Swift réflexion ne soit pas une priorité élevée pour Apple pour le moment. Mais à part @stevex réponse il y a une autre fonction de la bibliothèque standard qui aide.
À partir de la version bêta 6 _stdlib_getTypeName
obtient le nom de type mutilé d'une variable. Collez ceci dans un terrain de jeu vide:
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 sortie est:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
entrée de blog d'Ewan Swick aide à déchiffrer ces chaînes:
par exemple. _TtSi
représente le type interne Int
de Swift.
Mike Ash a une excellente entrée de blog couvrant le même sujet .
Vous voudrez peut-être envisager d'utiliser toString () à la place. Il est public et fonctionne exactement comme _ stdlib_getTypeName () à la différence qu'il fonctionne également sur AnyClass, par exemple. dans un terrain de jeu entrer
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"