ProgrammationDéveloppeur iOS, Middle/Senior

Qu'est-ce que les types opaques (some) en Swift, à quoi servent-ils et quand faut-il les utiliser à la place des types de protocole ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question : Les types opaques (some) ont été introduits avec Swift 5.1 et ouvrent une nouvelle façon d'abstraire le type de retour d'une fonction ou d'une propriété, lorsque le type est connu du compilateur mais caché à l'utilisateur. C'est une alternative aux existentials de protocole (any Protocol), mais avec une liaison stricte à un type spécifique à l'intérieur de la fonction.

Problème : Lorsque la fonction retourne un protocole avec un associatedtype (par exemple, Sequence), on ne peut pas écrire directement :

func makeNumberSequence() -> Sequence { ... } // erreur

Les existentials de protocole permettent de retourner n'importe quelle implémentation, mais ne garantissent pas le même type à chaque appel :

func foo() -> any View { ... }

Cela mène à de l'imprévisibilité et à une faible sécurité de type.

Solution : Utiliser le type de résultat opaque :

func makeNumbers() -> some Sequence { [1, 2, 3] }

Maintenant, le compilateur connaît exactement le type de retour, mais il est caché à l'extérieur. Cela permet des optimisations de performance, une sécurité accrue, facilite l'utilisation du DSL SwiftUI et aide à l'échange de types entre les modules.

Caractéristiques clés :

  • Le type concret à l'intérieur du type opaque est toujours le même
  • Ne prend pas en charge associatedtype à l'endroit de l'utilisation, mais dans la définition
  • Utilisé pour construire des API déclaratives (par exemple SwiftUI)

Questions pièges.

Les types opaques peuvent-ils être utilisés pour stocker des valeurs (comme des propriétés de classe) ?

Non. Les types opaques ne s'appliquent qu'aux valeurs de retour des fonctions ou des propriétés calculées. Pour stocker une valeur ou un tableau de valeurs, on utilise les existentials (any Protocol).

Les différentes branches d'une même fonction peuvent-elles retourner différents types avec some ?

Non. Le compilateur exige que toutes les branches retournent le même type concret, sinon une erreur se produira :

func foo(flag: Bool) -> some Sequence { if flag { return [1, 2, 3] } else { return ["a", "b", "c"] // erreur } }

Peut-on utiliser some pour identifier le type de retour entre plusieurs fonctions ?

Non. Chaque fonction avec some retourne son propre type caché unique, même si en réalité c'est le même tableau. Utiliser le résultat d'une fonction comme paramètre dans une autre n'est pas possible si les deux utilisent some avec différents protocoles ou différents types cachés.

Erreurs typiques et anti-patterns

  • Essayer de retourner différents types via some (erreur de compilation)
  • Utiliser some là où des existentials de protocole sont requis (par exemple, pour stocker des états)
  • Manquer des optimisations en continuant à utiliser les anciens types de protocole

Exemple de la vie réelle

Cas négatif

Dans un projet, tout est retourné via any Protocol, les collections perdent leur typage, des bugs apparaissent lors du downcast, ce qui ralentit l'optimisation compile-time.

Avantages :

  • Architecture flexible avec possibilité de combiner différents types

Inconvénients :

  • Perte de la sécurité de type, diminution de l'efficacité, problèmes de casts

Cas positif

Dans la conception SwiftUI, les composants retournent some View, chaque module définit clairement son type interne. La taille du bundle est réduite, la compilation est accélérée.

Avantages :

  • Amélioration des performances, augmentation de la sécurité de type

Inconvénients :

  • Perte de flexibilité dans le besoin de stockage dynamique