@ViewBuilder — je anotace result builderu v SwiftUI, určená pro deklarativní vytváření hierarchie View. Podle Apple Developer Documentation, 2024, převádí @ViewBuilder blok kódu s více výrazy a podmíněnou logikou na jediný typ View, srozumitelný pro kompilátor Swift. Bez této anotace by nebylo možné používat známou deklarativní syntaxi SwiftUI s if/else a několika prvky v těle body.
Hlavní body
@ViewBuilder — je anotace implementující vzor result builder (SE-0289), která umožňuje SwiftUI shromáždit několik View do jedné kompozice pomocí deklarativní syntaxe. Automaticky zabalí více výrazů, podmíněné konstrukce a volitelné hodnoty do odpovídajících typů: TupleView, ConditionalContent, OptionalContent.
Před příchodem result builderu museli vývojáři ručně zabalovat prvky do VStack nebo HStack a pro podmíněnou logiku používat ternární operátory nebo tovární metody. @ViewBuilder učinil syntaxi SwiftUI výstižnou a čitelnou, umožňujíc psaní kódu, který vypadá jako běžný Swift s if/else a cykly.
Podle Swift Evolution SE-0289 jsou result builders obecným mechanismem, který není vázán na SwiftUI. @ViewBuilder je jednou z implementací tohoto mechanismu, vedle @StringBuilder pro vytváření řetězců a knihovních implementací pro jiné DSL. V SwiftUI se @ViewBuilder používá nejen pro body, ale také pro parametry uzávěrů kontejnerů (VStack, HStack, ZStack, List).
V imperativním UIKit imperativně vytváříte UIView, konfigurujete jeho vlastnosti a přidáváte jej do hierarchie přes addSubview. V SwiftUI s @ViewBuilder deklarativně popisujete, která View mají být zobrazena, a SwiftUI sám spravuje vytváření, aktualizaci a odstraňování prvků na základě změn stavu.
Result builder — je mechanismus Swift, který převádí sekvenci výrazů na jedinou složenou hodnotu prostřednictvím statických metod buildBlock, buildOptional, buildEither a dalších. Když kompilátor uvidí anotaci @ViewBuilder, automaticky aplikuje tyto metody na blok kódu během kompilace.
@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 přijímá 1 až 10 výrazů a vrací TupleView. Každá arita (počet výrazů) má svůj vlastní overload buildBlock: od buildBlock<C0> do buildBlock<C0, C1, ..., C9>. Právě proto je počet prvků v jednom bloku @ViewBuilder omezen na 10.
buildEither (first/second) zpracovává konstrukce if/else. Každá větev je předána odpovídající metodě a výsledek je zabalen do ConditionalContent — typu, který skrývá konkrétní typy větví a poskytuje jednotné rozhraní pro SwiftUI.
V SwiftUI je vlastnost body již implicitně anotována @ViewBuilder — tuto anotaci v kódu nevidíte, ale kompilátor ji automaticky aplikuje. Pro uživatelské vlastnosti vracející více View nebo pro parametry uzávěrů je však třeba anotaci explicitně uvést.
Omezení 1 — 10 prvků v bloku. Toto je nejznámější omezení @ViewBuilder. Pokud potřebujete zobrazit více než 10 prvků na jedné úrovni, kompilátor vyvolá chybu. Lze to obejít pomocí Group, ForEach, List nebo rozdělením na podkomponenty. Group nepřidává vizuální vnoření, ale každý Group se počítá jako jeden prvek.
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")
}
}
}
Omezení 2 — nedostatek podpory pro některé konstrukce. @ViewBuilder nepodporuje do/catch, guard, for-in (bez ForEach) a další řídicí konstrukce. Pro cykly používejte ForEach s identifikovatelnými daty. Pro zpracování chyb používejte samostatná View přijímající Result nebo volitelné hodnoty.
Omezení 3 — obtížnost ladění. Při chybách v @ViewBuilder generuje kompilátor rozsáhlé zprávy, ve kterých je obtížné najít hlavní příčinu. Typické problémy: nesoulad typů ve větvích if/else, překročení limitu 10 prvků nebo chybějící požadovaný overload buildBlock.
Vzor 1: podmíněné zobrazení pomocí if/else. Nejčastější scénář použití @ViewBuilder. Umožňuje zobrazovat různá View v závislosti na stavu bez použití ternárních operátorů nebo továrních metod.
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)
}
}
}
Vzor 2: @ViewBuilder v parametrech funkcí a inicializátorů. Používá se pro vytváření znovupoužitelných kontejnerů, které přijímají podřízená View prostřednictvím uzávěru. Toto je standardní vzor pro knihovny a UI komponenty.
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)
}
}
Vzor 3: kompozice s ForEach. @ViewBuilder správně pracuje s ForEach, umožňujíc dynamické generování prvků z pole dat. Každý prvek ForEach se počítá jako jeden výraz v kontextu @ViewBuilder.
Vlastní ViewBuilder — je uživatelská funkce nebo vlastnost anotovaná @ViewBuilder, která vrací some View. Takové funkce umožňují zapouzdřit složitou logiku zobrazení a znovu ji použít v různých částech aplikace.
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
}
}
}
// Použití:
FormRow(label: "Name") {
TextField("Enter name", text: $name)
}
FormRow(label: "Gender") {
Picker("Select", selection: $gender) {
Text("Muž").tag(Gender.male)
Text("Žena").tag(Gender.female)
}
}
Důležité pravidlo: vlastní funkce s @ViewBuilder musí vracet some View, nikoli konkrétní typ nebo protokol View. Pouze opaque typ umožňuje skrýt konkrétní implementaci a zachovat flexibilitu kompozice.
Výkon: vlastní funkce @ViewBuilder nepřidávají režii ve srovnání s přímým kódem v body. Kompilátor inlineuje volání a optimalizuje výsledný kód. Rozdělení body na funkce @ViewBuilder zlepšuje čitelnost bez ztráty výkonu.
Často kladené otázky
@ViewBuilder — je anotace result builderu, která převádí blok kódu s více výrazy a podmínkami na jediný typ View. Umožňuje používat známou syntaxi Swift (if/else, switch, volitelné výrazy) uvnitř deklarativního UI SwiftUI.
Omezení souvisí s implementací buildBlock — pro každou aritu od 1 do 10 existuje samostatný overload metody. Swift nepodporuje variadic generics, takže počet overloadů je pevný. Pro obejití použijte Group, ForEach nebo podkomponenty.
Ne, protokol View implicitně aplikuje @ViewBuilder na vlastnost body. Pro uživatelské vlastnosti, metody a parametry uzávěrů vracející více View je však třeba anotaci explicitně uvést. Bez ní kompilátor nebude schopen zpracovat více výrazů.
Pro volitelné výrazy se používá metoda buildIf, která přijímá volitelný View a vrací jej, pokud hodnota existuje. Pokud je hodnota nil — buildIf vrací nil a prvek se nezobrazí. To umožňuje použití if let v těle body.
Ano, od Swift 5.9 @ViewBuilder podporuje switch prostřednictvím metody buildExpression. Kompilátor převádí každou větev case na odpovídající volání buildEither. Podpora switch dělá kód čitelnějším ve srovnání s vnořenými konstrukcemi if/else.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také