Réflexion et introspection en Swift : plongez au cœur du code
\n\nVous êtes-vous déjà demandé comment Swift « voit » ses propres structures et classes ? Comment connaître à la volée le type d'un objet, ses propriétés ou même la signature d'une méthode sans rien savoir à l'avance ? Bienvenue dans le monde de la réflexion et de l'introspection — deux mécanismes puissants qui transforment le Swift typé statiquement en un outil flexible pour la métaprogrammation.
\n\nAujourd'hui, nous n'allons pas simplement aborder la théorie. Nous allons écrire du code qui s'explore lui-même, apprendre à vérifier dynamiquement des protocoles et même sérialiser des objets sans Codable. C'est parti !
\n\nQu'est-ce que la réflexion et l'introspection ? Ne confondez pas ces concepts
\n\nCommençons par une terminologie claire pour ne pas vous perdre dans les méandres du runtime Swift.
\n\n- \n
- L'introspection est la capacité d'un programme à « se regarder lui-même » pendant l'exécution : connaître le type d'un objet, le nombre de propriétés, les noms des méthodes. En Swift, cela est implémenté via le protocole
Mirroret les opérateursis,as?,type(of:). \n - La réflexion est un concept plus large. Il ne s'agit pas seulement d'observer, mais aussi d'influencer la structure du programme à la volée : appeler des méthodes par leur nom, modifier des propriétés, créer de nouveaux types. En Swift, la réflexion est limitée (contrairement à Python ou Ruby), mais ses possibilités sont impressionnantes. \n
La principale différence : l'introspection est une lecture, la réflexion est une lecture + écriture. Swift se positionne comme un langage sûr, donc la réflexion complète (comme en Objective-C) n'est pas disponible pour les types Swift purs. Mais pour les classes héritant de NSObject, davantage de possibilités s'ouvrent.
Les outils d'introspection en Swift : du simple au complexe
\n\n1. Les opérateurs is et as? — les classiques
\n\nLa façon la plus simple de connaître le type d'un objet est d'utiliser la vérification avec is :
let valeur: Any = "Bonjour, Swift !"\n\nif valeur is String {\n print("C'est une chaîne !")\n}\n\nif let nombre = valeur as? Int {\n print("C'est un nombre : \\(nombre)")\n} else {\n print("Ce n'est pas un nombre")\n}\n\nIci, nous utilisons is pour vérifier le type et as? pour un cast sécurisé. C'est la base de toute introspection en Swift — vous demandez constamment à l'objet : « Qui es-tu ? ».
2. type(of:) — connaître le type dynamiquement
\n\nLa fonction type(of:) retourne le métatype (Any.Type) de la valeur passée. C'est utile lorsque vous avez besoin du type dynamique exact, et non du type statique déclaré :
class Animal { }\nclass Chien: Animal { }\n\nlet animal: Animal = Chien()\nprint(type(of: animal)) // Chien\n\n// Comparaison de types\nif type(of: animal) == Chien.self {\n print("C'est bien un chien !")\n}\n\nNotez que type(of:) retourne le type dynamique, et non le type statique (Animal). C'est une différence clé par rapport à Self.
3. Mirror — une vision aux rayons X pour les objets
\n\nEt maintenant, le plus intéressant. Mirror est une structure qui permet de regarder à l'intérieur de n'importe quel objet et d'obtenir la liste de ses propriétés, leurs noms et leurs valeurs. Un véritable outil de réflexion en Swift.
Exemple de base :
\n\nstruct Utilisateur {\n let nom: String\n var age: Int\n private var cleSecrete: String\n}\n\nlet utilisateur = Utilisateur(nom: "Alexandre", age: 30, cleSecrete: "abc123")\nlet mirror = Mirror(reflecting: utilisateur)\n\nprint("Type de l'objet : \\(mirror.subjectType)")\nprint("Nombre de propriétés : \\(mirror.children.count)")\n\nfor enfant in mirror.children {\n if let etiquette = enfant.label {\n print("\\(etiquette) : \\(enfant.value)")\n }\n}\n\nRésultat :
\nType de l'objet : Utilisateur\nNombre de propriétés : 3\nnom : Alexandre\nage : 30\ncleSecrete : abc123\n\nNotez que Mirror voit même les propriétés privées ! C'est puissant, mais aussi dangereux — ne l'utilisez pas à la légère.