ProgrammationDéveloppeur iOS senior

Qu'est-ce que les 'types opaques' (some) en Swift, quand et pourquoi les utiliser, et en quoi diffèrent-ils des protocoles avec associated type ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question :

En Swift jusqu'à la version 5, lors du retour d'une valeur correspondant à un protocole avec associated type, on se heurtait souvent à des limitations — le type ne pouvait pas être utilisé directement comme type de retour, une érasion de type était nécessaire. Pour améliorer la lisibilité et les performances, les types opaques ont été introduits — des valeurs de retour via le mot-clé some, permettant de décrire des abstractions dans les interfaces publiques.

Problème :

Quand il faut cacher le type réel de la valeur de retour, tout en conservant une abstraction via un protocole, mais éviter les coûts de dispatch dynamique et d'érosion de type. Par exemple, en retournant des collections, des séquences, des composants de vue.

Solution :

Les types opaques permettent de retourner un type conforme à un protocole, en cachant son implémentation concrète. Le compilateur connaît le type réel, mais la partie appelante ne le connaît pas.

Exemple :

protocol Shape { func area() -> Double } struct Circle: Shape { var radius: Double func area() -> Double { Double.pi * radius * radius } } func makeCircle() -> some Shape { return Circle(radius: 3) } let s = makeCircle() print(s.area()) // fonctionne

Caractéristiques clés :

  • Le type opaque — toujours le même type, caché derrière le protocole, déclaré dans le retour via some
  • Plus rapide et plus stricte que l'érosion de type, permet de travailler avec des associated types dans les protocoles
  • N'autorise pas le retour de types différents dans différentes branches (le type doit être le même pour tous les retours)

Questions pièges.

En quoi un type opaque (some Protocol) diffère-t-il d'un type de retour Protocol ?

Le type opaque a une implémentation concrète lors de la compilation (bien qu'elle soit cachée de l'extérieur). Lors du retour d'un Protocol, le dispatch dynamique est utilisé, il n'y a pas de sécurité de type s'il y a un associated type.

Peut-on retourner des types différents en utilisant some Protocol dans une seule fonction ?

Non. Tous les retours doivent retourner le même type réel :

func maker(flag: Bool) -> some Shape { if flag { return Circle(radius: 3) } else { return Square(size: 2) // Erreur : le type de retour ne correspond pas } }

Un associatedtype dans un Protocole peut-il être utilisé via some Protocol ?

Oui. C'est précisément pour cela (avant tout) qu'un type opaque est nécessaire :

protocol View { associatedtype Body } func makeView() -> some View { /* ... */ }

Erreurs typiques et anti-patrons

  • Confusion entre some Protocol et Protocol — cas et limitations différents
  • Violation de la règle d'homogénéité du type de retour dans toutes les branches
  • Utilisation de some là où un protocole ou un typealias serait plus simple

Exemple pratique

Cas négatif

Une fonction retourne un protocole sans opaque, ne permettant pas d'utiliser des méthodes avec associatedtype, nécessitant une érosion de type complexe, le code ne compile pas ou fonctionne de manière non optimale.

Avantages :

  • Flexibilité des abstractions de type AnySequence

Inconvénients :

  • Perte de sécurité de type, faible performance
  • Les types associés ne fonctionnent pas

Cas positif

ViewBuilder dans SwiftUI utilise some View, cachant les détails, augmentant la sécurité des types, améliorant la vitesse de compilation et d'exécution.

Avantages :

  • API lisible, sécurité de type, pas de dispatch dynamique
  • Simplicité de maintenance

Inconvénients :

  • Impossible de retourner des types différents dans une même fonction