Result Builder ist ein Swift-Attribut, das über das Protokoll @resultBuilder implementiert wird und eine Sequenz von Ausdrücken in einen zusammengesetzten Wert umwandelt. Der Compiler wandelt Codeblöcke mit Kontrollstrukturen if, for, switch in Aufrufe statischer Builder-Methoden um — buildBlock, buildEither, buildArray. Laut dem Swift Evolution Proposal SE-0289 (2022) ermöglichen Result Builders die Erstellung deklarativer DSLs innerhalb von Swift ohne externe Parser. Das bekannteste Beispiel ist @ViewBuilder in SwiftUI, wo der View-Body aus bedingten und zyklischen Elementen in einem deklarativen Stil aufgebaut wird.
Wichtige Punkte
TupleView umif/else, switch, for-in über die Methoden buildOptional, buildEither, buildArrayResult Builder (früher bekannt als Function Builders) ist ein Swift-Mechanismus, der eine durch Zeilenumbrüche getrennte Sequenz von Ausdrücken in einen einzelnen Wert umwandelt. Er wird mit dem Attribut @resultBuilder deklariert, das auf eine Struktur angewendet wird, die statische Transformationsmethoden implementiert.
Vor Result Builders war die deklarative Syntax des SwiftUI-Bodys unmöglich. Statt einer kompakten Liste von Views müssten Entwickler TupleView-Aufrufe manuell schreiben. Result Builder umschließt automatisch jeden Ausdruck, unterstützt Verzweigungen und Schleifen und verbirgt die Komplexität der Komposition vor dem Entwickler.
Laut Swift Evolution SE-0289, angenommen 2022, ist der Result Builder eine Weiterentwicklung der Function-Builders-Idee (SE-0258, Swift 5.1). Hauptänderungen: Umbenennung von @_functionBuilder in @resultBuilder und Erweiterung auf Funktionsparameter, wodurch Builder für beliebige Closure-Argumente verwendet werden können, nicht nur für View-Bodies.
Verwenden Sie Result Builders, wenn Sie Benutzern Ihrer Bibliothek eine deklarative Syntax zum Erstellen komplexer Strukturen bieten müssen — Konfigurationen, Abfragen, UI-Komponenten — ohne imperativen Assembly-Code schreiben zu müssen.
Der Swift-Compiler wandelt jeden mit @resultBuilder markierten Codeblock in eine Sequenz von Aufrufen statischer Builder-Methoden um. Betrachten wir einen einfachen Builder, der Strings verkettet:
@resultBuilder
struct StringBuilder {
static func buildBlock(_ parts: String...) -> String {
parts.joined(separator: " ")
}
}
Verwendung dieses Builders — jeder String in einer separaten Zeile wird mit einem Leerzeichen verkettet:
@StringBuilder
func greeting() -> String {
"Hello"
"World"
"from"
"Swift"
}
// Der Compiler wandelt dies um in:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// Ergebnis: "Hello World from Swift"
Der Compiler gruppiert aufeinanderfolgende Ausdrücke und übergibt sie als variadische Parameter an buildBlock. Wenn zwischen Ausdrücken ein if erscheint, ruft der Compiler zur Verzweigung buildOptional oder buildEither auf. Für for-in-Schleifen ruft er buildArray auf. So wird normaler Swift-Code in eine Aufrufkette umgewandelt, die den endgültigen Wert konstruiert.
Jeder Result Builder definiert eine Reihe statischer Methoden, die der Compiler während der Transformation aufruft. Die wichtigsten Methoden:
| Methode | Zweck | Wann aufgerufen |
|---|---|---|
| buildBlock | Kombiniert eine Sequenz von Ausdrücken | Für jeden Block ohne Verzweigung |
| buildOptional | Behandelt if ohne else | Wenn if ohne else vorkommt |
| buildEither(first:) | Erster Zweig von if-else | Bei if mit else |
| buildEither(second:) | Zweiter Zweig von if-else | Bei if mit else |
| buildArray | Behandelt for-in-Schleifen | Wenn for-in vorhanden ist |
| buildExpression | Wandelt einzelne Ausdrücke um | Für jeden Ausdruck vor der Übergabe an buildBlock |
| buildFinalResult | Endgültige Transformation | Vor der Rückkehr aus dem Closure |
Eine minimale Implementierung erfordert nur buildBlock mit variadischen Parametern — dies ist für Blöcke ohne Verzweigung ausreichend. Das Hinzufügen von buildOptional und buildEither ermöglicht die Unterstützung bedingter Konstrukte, und buildArray für Schleifen. Laut der Swift-Dokumentation (2025) wird empfohlen, alle Methoden für maximale DSL-Flexibilität zu implementieren.
buildExpression ermöglicht die Annahme von Ausdrücken verschiedener Typen und deren Umwandlung in einen einzigen Builder-Typ. Beispielsweise akzeptiert buildExpression in @ViewBuilder Text, Image, Button und wandelt sie in den gemeinsamen View-Typ um.
Betrachten wir die Erstellung eines Builders zum Konstruieren von HTML-Strings. Dieses DSL ermöglicht das direkte Schreiben von deklarativem HTML in Swift:
@resultBuilder
enum HTMLBuilder {
static func buildBlock(_ components: String...) -> String {
components.joined()
}
static func buildOptional(_ component: String?) -> String {
component ?? ""
}
static func buildEither(first component: String) -> String {
component
}
static func buildEither(second component: String) -> String {
component
}
static func buildArray(_ components: [String]) -> String {
components.joined()
}
}
Verwendung des benutzerdefinierten Builders zur HTML-Generierung:
func div(@HTMLBuilder _ content: () -> String) -> String {
"<div>\(content())</div>"
}
func p(_ text: String) -> String {
"<p>\(text)</p>"
}
let page = div {
p("Hello")
p("World")
if showFooter {
p("Fußzeile")
}
}
// Ergebnis: <div><p>Hello</p><p>World</p><p>Footer</p></div>
Laut dem Artikel „Building Custom Result Builders in Swift“ von Swift.org (2025) werden benutzerdefinierte Builder in Bibliotheken zum Erstellen von Konfigurationsdateien, UI-Komponenten, Datenzuordnungen und sogar Datenbankabfragen verwendet — überall dort, wo eine deklarative Syntax mit Verzweigungsunterstützung benötigt wird.
@ViewBuilder ist ein in SwiftUI integrierter Result Builder, der auf den content-Parameter der meisten Container-Views angewendet wird: VStack, HStack, ZStack, Group, List und die body-Eigenschaft selbst. Er ermöglicht das Schreiben mehrerer Views in separaten Zeilen ohne Kommas oder Wrapper.
@ViewBuilder implementiert alle Result-Builder-Methoden, einschließlich Unterstützung für if-else, switch und for-in. Wenn eine Bedingung wahr ist, gibt buildEither(first:) eine View zurück; wenn falsch, gibt buildEither(second:) eine andere zurück. Beide Zweige müssen denselben Typ zurückgeben, aber SwiftUI verwendet intern AnyView oder Typverwischung durch ConditionalContent.
struct GreetingView: View {
let isLoggedIn: Bool
var body: some View {
VStack {
Image(systemName: "person.circle")
Text("Profil")
.font(.title)
if isLoggedIn {
Text("Willkommen zurück!")
.foregroundColor(.green)
} else {
Button("Anmelden") { }
}
}
}
}
Ohne @ViewBuilder würde derselbe Code Group für jede bedingte Sektion oder die Verwendung von AnyView erfordern, was die Leistung beeinträchtigt. @ViewBuilder wählt automatisch die effizienteste Darstellung — ConditionalContent oder TupleView — für jede Kombination aus.
Die erste Einschränkung ist die maximale Anzahl von Ausdrücken in buildBlock. Die Swift-Standardbibliothek definiert buildBlock-Überladungen für 2–10 Ausdrücke. Wenn ein Block mehr als 10 Ausdrücke enthält, gibt der Compiler einen Fehler aus. Die Lösung ist die Gruppierung durch Group oder VStack zur Aufteilung in Unterblöcke.
Die zweite Einschränkung ist die fehlende Unterstützung für Variablen und Zuweisungen innerhalb des Builder-Blocks. Innerhalb von @ViewBuilder kann let x = 5 nicht deklariert werden. Alle Ausdrücke müssen Ausdrücke sein, die einen Wert des Builder-Typs zurückgeben. Für Zwischenberechnungen verwenden Sie Berechnungen außerhalb des Builders oder buildExpression mit Unterstützung für verschiedene Typen.
Die dritte Einschränkung ist die Komplexität der Fehlersuche. Compiler-Fehler innerhalb eines Result Builders erzeugen oft verwirrende Meldungen, insbesondere bei Typkonflikten in if/else-Zweigen. Verwenden Sie explizite Rückgabetypen und AnyView zur Fehlersuche, obwohl letzteres die Leistung beeinträchtigt. Laut Hacking with Swift (2025) ist ein praktischer Tipp, mit einem einfachen Builder ohne Verzweigung zu beginnen und nach und nach Unterstützung für bedingte Konstrukte hinzuzufügen.
Häufig gestellte Fragen
Result Builder ist ein Swift-Attribut, das eine Sequenz von Ausdrücken durch statische Methoden in einen Ergebniswert umwandelt. Es ermöglicht die Erstellung deklarativer DSLs, das bekannteste Beispiel ist @ViewBuilder in SwiftUI zum Erstellen von View-Hierarchien ohne imperativen Code.
Deklarieren Sie eine Struktur mit dem Attribut @resultBuilder und implementieren Sie mindestens die Methode buildBlock. Um Bedingungen zu unterstützen, fügen Sie buildOptional und buildEither hinzu; für Schleifen fügen Sie buildArray hinzu. Verwenden Sie das Builder-Attribut vor dem Closure-Parameter in einer Funktion.
Nur buildBlock ist obligatorisch. Alle anderen Methoden — buildOptional, buildEither, buildArray, buildExpression, buildFinalResult — sind optional und fügen Unterstützung für entsprechende Konstrukte hinzu. Je mehr Methoden implementiert sind, desto flexibler ist das DSL.
@ViewBuilder ist eine konkrete Implementierung des Result Builders für das View-Protokoll. Es ist in SwiftUI als Struktur mit dem Attribut @resultBuilder definiert und bietet buildBlock-Methoden für verschiedene Anzahlen von Views (TupleView), buildEither für ConditionalContent und buildArray für ForEach.
Ja, die standardmäßigen buildBlock-Überladungen unterstützen bis zu 10 Ausdrücke. Bei Überschreitung verwenden Sie verschachtelte Container (Group, VStack) zur Aufteilung in Unterblöcke. Ein benutzerdefinierter Builder kann einen variadischen buildBlock ohne Begrenzung definieren.
Zusammenfassung
buildBlock, buildEither, buildOptional, buildArray je nach KontrollstrukturenWir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch