@ViewBuilder : qu'est-ce que c'est, result builder pour View dans SwiftUI

Auteur : IT Sectr Publié le : 2026-06-24 Temps de lecture : 7 min

@ViewBuilder est une annotation result builder dans SwiftUI conçue pour la construction déclarative de hiérarchies de View. Selon Apple Developer Documentation, 2024, @ViewBuilder transforme un bloc de code avec de multiples expressions et une logique conditionnelle en un seul type View compréhensible par le compilateur Swift. Sans cette annotation, il serait impossible d'utiliser la syntaxe déclarative familière de SwiftUI avec if/else et de multiples éléments dans le body.

Points clés

  • @ViewBuilder — result builder qui compose plusieurs Views en une composition sans conteneurs supplémentaires
  • buildBlock — encapsule une séquence d'expressions dans un TupleView jusqu'à 10 éléments
  • buildEither — crée ConditionalContent pour les branches if/else et switch
  • Limitation — jusqu'à 10 éléments dans un seul bloc sans Group ou ForEach
  • Application implicite — body est déjà encapsulé dans @ViewBuilder, les fonctions personnalisées nécessitent une annotation explicite

Qu'est-ce que @ViewBuilder dans SwiftUI ?

@ViewBuilder est une annotation qui implémente le patron result builder (SE-0289), permettant à SwiftUI de composer plusieurs Views en une seule composition en utilisant une syntaxe déclarative. Elle encapsule automatiquement les expressions multiples, les constructions conditionnelles et les valeurs optionnelles dans leurs types correspondants : TupleView, ConditionalContent, OptionalContent.

Avant l'arrivée des result builders, les développeurs devaient encapsuler manuellement les éléments dans VStack ou HStack, et utiliser des opérateurs ternaires ou des méthodes fabriques pour la logique conditionnelle. @ViewBuilder a rendu la syntaxe SwiftUI concise et lisible, permettant d'écrire du code qui ressemble à du Swift normal avec if/else et des boucles.

Selon Swift Evolution SE-0289, les result builders sont un mécanisme général non lié à SwiftUI. @ViewBuilder est une implémentation de ce mécanisme, aux côtés de @StringBuilder pour la construction de chaînes et des implémentations de bibliothèques pour d'autres DSL. Dans SwiftUI, @ViewBuilder est utilisé non seulement pour body, mais aussi pour les paramètres de closure des conteneurs (VStack, HStack, ZStack, List).

Différence avec l'approche impérative

Dans l'UIKit impératif, vous créez explicitement un UIView, configurez ses propriétés et l'ajoutez à la hiérarchie via addSubview. Dans SwiftUI avec @ViewBuilder, vous décrivez déclarativement quelles Views doivent être affichées, et SwiftUI gère la création, la mise à jour et la suppression des éléments en fonction des changements d'état.

Comment fonctionne @ViewBuilder : result builder

Result builder est un mécanisme de Swift qui transforme une séquence d'expressions en une seule valeur composite via les méthodes statiques buildBlock, buildOptional, buildEither et autres. Lorsque le compilateur voit l'annotation @ViewBuilder, il applique automatiquement ces méthodes au bloc de code pendant la compilation.

swift
@resultBuilder
struct ViewBuilder {
    static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)>
    static func buildIf<C>(_ c: C?) -> C?
    static func buildEither<T, F>(first: T) -> ConditionalContent<T, F>
    static func buildEither<T, F>(second: F) -> ConditionalContent<T, F>
}

buildBlock accepte de 1 à 10 expressions et retourne un TupleView. Chaque arité (nombre d'expressions) a sa propre surcharge de buildBlock : de buildBlock à buildBlock. C'est pourquoi le nombre d'éléments dans un seul bloc @ViewBuilder est limité à 10.

buildEither (first/second) traite les constructions if/else. Chaque branche est passée à la méthode correspondante, et le résultat est encapsulé dans ConditionalContent — un type qui cache les types spécifiques des branches et fournit une interface unifiée pour SwiftUI.

Comportement implicite de @ViewBuilder

Dans SwiftUI, la propriété body est déjà implicitement annotée avec @ViewBuilder — vous ne voyez pas cette annotation dans le code, mais le compilateur l'applique automatiquement. Cependant, pour les propriétés personnalisées qui retournent plusieurs Views, ou pour les paramètres de closure, l'annotation doit être spécifiée explicitement.

Limitations de @ViewBuilder et comment les contourner

Limitation 1 — 10 éléments dans un bloc. C'est la limitation la plus connue de @ViewBuilder. Si vous devez afficher plus de 10 éléments au même niveau, le compilateur émettra une erreur. Les solutions incluent Group, ForEach, List ou la division en sous-composants. Group n'ajoute pas d'imbrication visuelle, mais chaque Group compte comme un élément.

swift
struct ManyElementsView: View {
    var body: some View {
        Group {
            Text("1"); Text("2"); Text("3")
            Text("4"); Text("5"); Text("6")
            Text("7"); Text("8"); Text("9")
        }
        Group {
            Text("10"); Text("11"); Text("12")
        }
    }
}

Limitation 2 — absence de support pour certaines constructions. @ViewBuilder ne supporte pas do/catch, guard, for-in (sans ForEach) et d'autres constructions de flux de contrôle. Pour les boucles, utilisez ForEach avec des données identifiables. Pour la gestion des erreurs, utilisez des Views séparées qui acceptent Result ou des valeurs optionnelles.

Limitation 3 — complexité de débogage. Lorsque des erreurs se produisent dans @ViewBuilder, le compilateur produit des messages verbeux dans lesquels il est difficile de trouver la cause racine. Problèmes typiques : incompatibilité de types dans les branches if/else, dépassement de la limite de 10 éléments ou absence de surcharges nécessaires de buildBlock.

Patrons d'utilisation de @ViewBuilder

Patron 1 : affichage conditionnel via if/else. Le cas d'utilisation le plus courant de @ViewBuilder. Permet d'afficher différentes Views en fonction de l'état sans utiliser d'opérateurs ternaires ou de méthodes fabriques.

swift
struct StatusView: View {
    var status: LoadStatus

    @ViewBuilder
    var body: some View {
        switch status {
        case .loading:
            ProgressView("Loading...")
        case .loaded(let data):
            DataView(data: data)
        case .error(let message):
            ErrorView(message: message)
        }
    }
}

Patron 2 : @ViewBuilder dans les paramètres de fonctions et d'initialiseurs. Utilisé pour créer des conteneurs réutilisables qui acceptent des Views enfants via une closure. C'est le patron standard pour les bibliothèques et les composants d'interface utilisateur.

swift
struct SectionCard<Content: View>: View {
    let title: String
    @ViewBuilder let content: Content

    var body: some View {
        VStack(alignment: .leading) {
            Text(title).font(.headline)
            content
        }
        .padding()
        .background(Color.gray.opacity(0.1))
        .cornerRadius(12)
    }
}

Patron 3 : composition avec ForEach. @ViewBuilder fonctionne correctement avec ForEach, permettant la génération dynamique d'éléments à partir d'un tableau de données. Chaque élément de ForEach compte comme une expression dans le contexte de @ViewBuilder.

Création d'un ViewBuilder personnalisé pour des composants réutilisables

ViewBuilder personnalisé est une fonction ou propriété définie par l'utilisateur annotée avec @ViewBuilder qui retourne some View. Ces fonctions permettent d'encapsuler une logique d'affichage complexe et de la réutiliser dans différentes parties de l'application.

swift
struct FormRow<Content: View>: View {
    let label: String
    @ViewBuilder let content: Content

    var body: some View {
        HStack {
            Text(label)
                .frame(width: 120, alignment: .trailing)
            content
        }
    }
}

// Utilisation :
FormRow(label: "Name") {
    TextField("Enter name", text: $name)
}

FormRow(label: "Gender") {
    Picker("Select", selection: $gender) {
        Text("Homme").tag(Gender.male)
        Text("Femme").tag(Gender.female)
    }
}

Règle importante : une fonction personnalisée avec @ViewBuilder doit retourner some View, pas un type concret ni le protocole View. Seul un type opaque permet de masquer l'implémentation concrète tout en préservant la flexibilité de composition.

Performance : les fonctions personnalisées @ViewBuilder n'ajoutent pas de surcharge par rapport au code direct dans body. Le compilateur inline les appels et optimise le code résultant. Diviser body en fonctions @ViewBuilder améliore la lisibilité sans sacrifier les performances.

Foire aux questions

Qu'est-ce que @ViewBuilder dans SwiftUI ?

@ViewBuilder est une annotation result builder qui transforme un bloc de code avec plusieurs expressions et conditions en un seul type View. Elle permet d'utiliser la syntaxe Swift familière (if/else, switch, expressions optionnelles) dans l'interface utilisateur déclarative de SwiftUI.

Pourquoi ne peut-on pas mettre plus de 10 éléments dans @ViewBuilder ?

La limitation vient de l'implémentation de buildBlock — il existe une surcharge séparée de la méthode pour chaque arité de 1 à 10. Swift ne supporte pas les génériques variadiques, donc le nombre de surcharges est fixe. Pour contourner cela, utilisez Group, ForEach ou des sous-composants.

Dois-je spécifier explicitement @ViewBuilder avant body ?

Non, le protocole View applique implicitement @ViewBuilder à la propriété body. Cependant, pour les propriétés personnalisées, les méthodes et les paramètres de closure qui retournent plusieurs Views, l'annotation doit être spécifiée explicitement. Sans elle, le compilateur ne pourra pas traiter les expressions multiples.

Comment @ViewBuilder gère-t-il les expressions optionnelles ?

Pour les expressions optionnelles, la méthode buildIf est utilisée, qui accepte une View optionnelle et la retourne si une valeur existe. Si la valeur est nil, buildIf retourne nil et l'élément n'est pas affiché. Cela permet d'utiliser if let à l'intérieur du body.

Peut-on utiliser @ViewBuilder avec switch ?

Oui, depuis Swift 5.9 @ViewBuilder supporte switch via la méthode buildExpression. Le compilateur transforme chaque branche case en appel buildEither correspondant. Le support de switch rend le code plus lisible par rapport aux constructions if/else imbriquées.

Résumé

  • @ViewBuilder — result builder pour la construction déclarative de hiérarchies View dans SwiftUI
  • buildBlock encapsule une séquence d'expressions dans TupleView (jusqu'à 10 éléments)
  • buildEither crée ConditionalContent pour les branches if/else et switch
  • buildIf gère les expressions optionnelles et if sans else
  • Group et ForEach aident à contourner la limite de 10 éléments par bloc
  • Les fonctions @ViewBuilder personnalisées améliorent la réutilisabilité sans perte de performance
  • @ViewBuilder est appliqué implicitement à body, mais nécessite une annotation explicite pour les paramètres

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.

Discuter du projet

Lisez aussi