Si une classe étend NSObject
, alors toute l'introspection et le dynamisme d'Objective-C fonctionnent. Cela inclut :
- La capacité de demander à une classe ses méthodes et ses propriétés, et d'invoquer des méthodes ou de définir des propriétés.
- La capacité d'échanger des implémentations de méthode (ajouter des fonctionnalités à toutes les instances).
- La capacité de générer et d'attribuer une nouvelle sous-classe à la volée (ajouter des fonctionnalités à une instance donnée)
Un inconvénient de cette fonctionnalité est le support des types de valeurs optionnels de 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 optionnels peuvent être énumérés partiellement en utilisant reflect/MirrorType, mais toujours pas modifiés.
Si une classe n'étend pas NSObject
, alors seul le nouveau, très limité (et en cours ?) fonctionnement de réflexion fonctionne (voir reflect/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'elle n'étend pas NSObject, ou utilise la directive '@objc', Swift utilise par défaut une expédition basée sur le statique et sur la table virtuelle. C'est plus rapide, cependant, en l'absence d'une machine virtuelle, elle n'autorise pas l'interception des méthodes à l'exécution. Cette interception est une partie fondamentale de Cocoa et est requise pour les types de fonctionnalités suivants :
- Les observateurs élégants de propriétés de Cocoa (les observateurs de propriétés sont intégrés directement dans le langage Swift).
- L'application non invasive de préoccupations transversales comme le logging, la gestion des transactions (c'est-à-dire la programmation orientée aspect).
- Les proxys, la délégation de messages, etc.
Il est donc recommandé que les classes dans les applications Cocoa/CocoaTouch soient implémentées avec Swift :
- Étendre à partir de NSObject. Le nouveau dialogue de classe dans Xcode oriente dans cette direction.
- Lorsque le surcoût d'une expédition dynamique entraîne des problèmes de performances, l'expédition statique peut être utilisée - dans des boucles serrées avec des appels à des méthodes avec des corps très petits, par exemple.
Résumé :
- Swift peut se comporter comme C++, avec une expédition statique/vtable rapide et une réflexion limitée. Cela le rend adapté aux applications de niveau inférieur ou intensives en performances, mais sans la complexité, la courbe d'apprentissage ou le risque d'erreur associés à C++
- Alors que Swift est un langage compilé, le style de messagerie de l'invocation de méthode ajoute l'introspection et le dynamisme que l'on retrouve dans des langages modernes comme Ruby et Python, tout comme Objective-C, mais sans la syntaxe héritée d'Objective-C.
Données de référence : Surcoût d'exécution pour les invocations de méthodes :
- statique : < 1.1ns
- vtable : ~ 1.1ns
- dynamique : ~4.9ns
(les performances réelles dépendent du matériel, mais les ratios resteront similaires).
De plus, l'attribut dynamique nous permet d'instruire explicitement Swift qu'une méthode doit utiliser une expédition dynamique, et supportera donc l'interception.
public dynamic func foobar() -> AnyObject {
}
1 votes
J'ai créé une classe d'aide pour la réflexion en Swift. Vous pouvez la trouver à : github.com/evermeer/EVReflection
2 votes
Ils ont supprimé reflect dans Swift 2.0. Voici comment je numérote les attributs et les valeurs Link