Opaque Type est un mécanisme de Swift qui permet à une fonction de retourner une valeur d’un certain type sans révéler le type concret au code appelant. Le mot-clé some dans le type de retour est l’exemple le plus célèbre : some View dans SwiftUI signifie « la fonction retourne un type qui se conforme à View, mais lequel exactement est un détail d’implémentation ». Un opaque type préserve l’identité du type (contrairement à un protocole en tant que type), ce qui permet au compilateur d’optimiser le code et garantit la cohérence du type retourné. Selon Swift Book, 2025, les opaque types résolvent le problème des protocoles avec types associés, permettant de retourner des valeurs de ces protocoles depuis des fonctions.
Points clés
Opaque Type est un type de retour déclaré avec le mot-clé some qui masque l’implémentation concrète du code appelant. L’appelant sait seulement que la valeur retournée est conforme à un protocole donné, mais ne sait pas exactement quel type se cache derrière some. Pendant ce temps, le compilateur connaît le type exact et l’utilise pour la distribution statique et l’optimisation.
Avant l’introduction des opaque types dans Swift 5.1 (SE-0244), il était impossible de retourner un protocole avec types associés depuis une fonction sans wrapper de boxing. Par exemple, le protocole Equatable a un type associé, et une fonction ne pouvait pas simplement retourner Equatable — le compilateur générait une erreur « le protocole ne peut être utilisé que comme contrainte générique ». Opaque type a résolu ce problème.
func makeInt() -> some Equatable {
return 42
}
func makeString() -> some Equatable {
return "Hello"
}
// Le compilateur sait que makeInt retourne Int
// makeInt() == makeString() — ❌ erreur, types différents
Les deux fonctions retournent some Equatable, mais les types concrets sont différents : Int et String. Essayer de les comparer avec == provoquera une erreur de compilation car un opaque type garantit qu’un appel spécifique retourne le même type, mais pas entre différentes fonctions. C’est une fonctionnalité, pas un bug : opaque type préserve l’identité du type là où un protocole en tant que type (any Equatable) la perd.
Generic et Opaque Type sont les deux faces d’une même pièce. Les génériques permettent au code appelant de choisir le type, tandis que opaque type permet à la fonction de masquer le type au code appelant. La différence réside dans la direction du contrôle.
| Caractéristique | Generic | Opaque some |
|---|---|---|
| Qui choisit le type | Code appelant | Fonction/méthode |
| Identité du type | Préservée (stable) | Préservée (stable) |
| Nombre de branches de retour | Une (via générique) | Même type dans toutes les branches |
| Utilisation | Algorithmes, structures de données | SwiftUI, méthodes d’usine |
Dans une fonction générique, l’appelant décide quel type utiliser. La fonction doit fonctionner avec tout T satisfaisant les contraintes. Pour opaque type, l’appelant ne connaît pas le type concret — l’implémentation prend la décision.
// Generic : l’appelant choisit le type
func identity<T>(_ value: T) -> T { value }
let x: Int = identity(42)
// Opaque : la fonction masque le type
func makeSomeEquatable() -> some Equatable { 42 }
let y = makeSomeEquatable()
Le choix entre generic et opaque type dépend de l’intention. Si le code appelant doit choisir le type, utilisez les génériques. Si la fonction doit masquer les détails d’implémentation, utilisez some. SwiftUI a choisi some View précisément parce que body doit être flexible en interne mais stable en externe.
some est un mot-clé Swift introduit dans Swift 5.1 (SE-0244). Il est utilisé en position de retour pour déclarer un opaque type, ainsi que dans les paramètres (SE-0341) et les propriétés. some garantit que le type concret est stable et connu du compilateur mais masqué du code externe.
À partir de Swift 5.7, some peut être utilisé non seulement en position de retour mais aussi dans les paramètres. some Equatable dans un paramètre signifie « cette fonction accepte tout type Equatable, mais tous les appels à l’intérieur d’un corps spécifique voient le même type ».
func areEqual(_ a: some Equatable, _ b: some Equatable) -> Bool {
// a et b — types potentiellement différents, == ne fonctionnera pas directement
return isEqual(a, b)
}
func isEqual<T: Equatable>(_ a: T, _ b: T) -> Bool {
return a == b
}
Utiliser some dans les paramètres offre une syntaxe plus concise par rapport à
any est un mot-clé Swift 5.6+ pour déclarer explicitement des types existentiels (protocole en tant que type). Contrairement à some, any efface l’identité du type : le compilateur ne sait pas quel type concret se cache derrière le protocole. Cela offre de la flexibilité (vous pouvez stocker différents types dans un même tableau), mais au prix des performances.
some — polymorphisme statique : le compilateur connaît le type concret, utilise la distribution directe et peut intégrer le code. any — polymorphisme dynamique : une table de méthodes virtuelles (conteneur existentiel) est utilisée, ce qui ajoute de l’indirection.
protocol Drawable {
func draw()
}
// some : le type statique est connu
func makeDrawable() -> some Drawable {
return Circle() // Type de retour unique
}
// any : dynamique, peut stocker différents types
var shapes: [any Drawable] = [Circle(), Square()]
shapes.append(Triangle())
Le choix entre some et any est un compromis entre performances et flexibilité. Some est plus rapide mais se limite à une seule implémentation. Any est plus flexible (vous pouvez mélanger les types) mais plus lent en raison de la distribution dynamique. Dans SwiftUI, body utilise toujours some View car le body de chaque View est un type concret.
Opaque Type résout un problème fondamental de Swift : les protocoles avec types associés (PAT) ne peuvent pas être utilisés directement comme type. Une fonction ne peut pas simplement retourner Collection — le compilateur exige de spécifier Element. some Collection résout cela en masquant le type associé.
Sans opaque type, retourner une Collection nécessiterait d’utiliser un type concret (Array
func makeReversedCollection<T>(
of array: [T]
) -> some Collection {
return array.reversed()
}
let result = makeReversedCollection(of: [1, 2, 3])
// result — ReversedCollection>, hidden from caller
for item in result {
print(item)
}
result peut être itéré, mais vous ne pouvez pas accéder directement aux propriétés de ReversedCollection. Cela protège l’encapsulation : si vous remplacez plus tard reversed() par une autre méthode avec une implémentation différente, le code appelant ne sera pas cassé. Opaque type vous donne la liberté de modifier l’implémentation sans modifier l’API.
some View est l’utilisation la plus célèbre de opaque type. Chaque View dans SwiftUI déclare body comme some View. Cela signifie que body retourne un type concret de View, mais le développeur n’a pas besoin de réfléchir à ce que c’est exactement — TupleView, Group, ModifiedContent ou tout autre type du framework.
Sans opaque type, body devrait retourner un type concret, par exemple ModifiedContent<Button<Text>, Padding>, ce qui est peu pratique. some View masque cette complexité. Le compilateur déduit le type exact de body automatiquement à la compilation.
struct ContentView: View {
var body: some View {
VStack {
Text("Bonjour")
.font(.title)
Button("Tapez-moi") {
print("Tapé")
}
}
.padding()
}
}
Le compilateur déduit body comme ModifiedContent<VStack<TupleView<(Text, Button<Text>)>>, Padding>. Le développeur voit some View. Si vous changez la disposition de VStack en HStack, le compilateur re-déduira automatiquement le type — aucune modification manuelle nécessaire. C’est la magie d’opaque type : le développeur se concentre sur la logique de l’interface, pas sur les types de composition.
Questions fréquentes
Opaque Type est un type déclaré avec le mot-clé some qui masque l’implémentation concrète du code appelant. Le compilateur connaît le type exact, mais le développeur utilisant la fonction ne voit que le protocole.
some est un opaque type avec identité statique : le compilateur connaît le type concret. any est un type existentiel avec distribution dynamique : l’identité du type est effacée. Some est plus performant, any est plus flexible.
some View masque le type concret complexe de body, que le compilateur déduit automatiquement. Cela libère le développeur de la nécessité d’écrire le type exact composé de wrappers génériques (VStack, Group, ModifiedContent).
Oui, à partir de Swift 5.7. Some dans les paramètres est un sucre syntaxique sur un paramètre générique. Cela simplifie les déclarations de fonctions, surtout lors du travail avec des protocoles où chaque paramètre some ne nécessite pas de
Le compilateur générera une erreur : opaque type exige que toutes les branches de retour retournent le même type concret. C’est intentionnel pour préserver l’identité du type. Si vous devez retourner différents types, utilisez any.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi