Swift soutient-il la réflexion? Existe-t-il quelque chose comme valueForKeyPath:
et setValue:forKeyPath:
pour les objets Swift?
En fait, a-t-il même un système de type dynamique, quelque chose comme obj.class
en Objective-C?
Swift soutient-il la réflexion? Existe-t-il quelque chose comme valueForKeyPath:
et setValue:forKeyPath:
pour les objets Swift?
En fait, a-t-il même un système de type dynamique, quelque chose comme obj.class
en Objective-C?
Réponses:
On dirait qu'il y a le début d'un 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
Mirror
cite le mot IDE
plusieurs fois.
_stdlib_getTypeName
peut vous aider.
Si une classe s'étend NSObject
, alors toute l'introspection et le dynamisme d'Objective-C fonctionnent. Ceci comprend:
Un inconvénient de cette fonctionnalité est la prise en charge des types de valeur optionnels Swift. Par exemple, les propriétés Int peuvent être énumérées et modifiées mais Int? les propriétés ne peuvent pas. Les types facultatifs peuvent être énumérés partiellement à l'aide de Reflect / MirrorType, mais toujours pas modifiés.
Si une classe ne s'étend pas NSObject
, alors seule la nouvelle réflexion très limitée (et en cours?) Fonctionne (voir refléter / MirrorType), ce qui ajoute une capacité limitée à demander à une instance sa classe et ses propriétés, mais aucune des fonctionnalités supplémentaires ci-dessus .
Lorsqu'il n'étend pas NSObject ou n'utilise pas la directive '@objc', Swift utilise par défaut une distribution basée sur statique et vtable. Ceci est plus rapide, cependant, en l'absence d'une machine virtuelle ne permet pas l'interception de méthode d'exécution. Cette interception est une partie fondamentale de Cocoa et est requise pour les types de fonctionnalités suivants:
Par conséquent, il est recommandé que les classes dans les applications Cocoa / CocoaTouch implémentées avec Swift:
Résumé:
Données de référence: surcharge d'exécution pour les appels de méthode:
(les performances réelles dépendent du matériel, mais les ratios resteront similaires).
De plus, l'attribut dynamic nous permet d'indiquer explicitement à Swift qu'une méthode doit utiliser la répartition dynamique et prendra donc en charge l'interception.
public dynamic func foobar() -> AnyObject {
}
La documentation parle d'un système de type dynamique, principalement
Type
et dynamicType
Voir Type de métatype (dans 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"
En supposant maintenant TestObject
s'étendNSObject
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 œuvre.
EDIT: J'avais apparemment tort, voir la réponse de stevex. Il existe une réflexion simple 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 de réflexion Swift ne soit pas une priorité pour Apple pour le moment. Mais en plus de la réponse @stevex, il existe une autre fonction dans 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
L'entrée de blog d'Ewan Swick aide à déchiffrer ces chaînes:
par exemple _TtSi
représente le Int
type interne de Swift .
Mike Ash a une excellente entrée de blog sur le même sujet .
Vous voudrez peut-être envisager d'utiliser toString () à la place. Il est public et fonctionne de la même manière que _stdlib_getTypeName () à la différence qu'il fonctionne également sur AnyClass , par exemple dans un Playground, entrez
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
Aucun reflect
mot-clé dans Swift 5, vous pouvez maintenant utiliser
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
désérialisation