Result Builder — un atribut Swift, implementat prin protocolul @resultBuilder, care transformă o secvență de expresii într-o valoare compusă. Compilatorul transformă blocurile de cod cu construcții de control if, for, switch în apeluri ale metodelor statice ale builderului — buildBlock, buildEither, buildArray. Conform propunerii Swift Evolution SE-0289 (2022), result builderii permit skapande de DSL-uri declarative în Swift fără analizatoare externe. Cel mai cunoscut exemplu — @ViewBuilder în SwiftUI, unde corpul view-ului este construit din elemente condiționale și ciclice în stil declarativ.
Principalele
TupleViewif/else, switch, for-in prin metodele buildOptional, buildEither, buildArrayResult Builder (cunoscut anterior ca function builders) — este un mecanism Swift care permite transformarea unei secvențe de expresii separate prin linie nouă într-o singură valoare. Este declarat cu atributul @resultBuilder aplicat unei structuri care implementează metode statice de transformare.
Înainte de apariția result builderilor, sintaxa declarativă a SwiftUI body era imposibilă. În locul unei liste compacte de view-uri, dezvoltatorul ar fi trebuit să scrie manual apeluri TupleView. Result Builder îmbracă automat fiecare expresie, suportă ramificare și bucle, ascunzând complexitatea compoziției de la dezvoltator.
Conform Swift Evolution SE-0289, adoptat în 2022, result builder este o evoluție a ideii function builders (SE-0258, Swift 5.1). Schimbările principale: redenumirea din @_functionBuilder în @resultBuilder și extinderea la parametrii de funcții, ceea ce a permis användning builderilor pentru orice argumente closure, nu doar pentru corpul view-ului.
Folosiți result builderi când doriți să oferiți utilizatorilor bibliotecii dvs. o sintaxă declarativă pentru construirea structurilor complexe — configurații, interogări, componente UI — fără a scrie cod imperativ de asamblare.
Compilatorul Swift transformă fiecare bloc de cod marcat cu @resultBuilder într-o secvență de apeluri ale metodelor statice ale builderului. Să considerăm cel mai simplu builder care concatenează șiruri:
@resultBuilder
struct StringBuilder {
static func buildBlock(_ parts: String...) -> String {
parts.joined(separator: " ")
}
}
användning acestui builder — fiecare linie pe un rând separat este concatenată printr-un spațiu:
@StringBuilder
func greeting() -> String {
"Hello"
"World"
"from"
"Swift"
}
// Kompilatorn omvandlar detta till:
// StringBuilder.buildBlock("Hello","World","from","Swift")
// Resultat: "Hello World from Swift"
Compilatorul grupează expresiile consecutive și le transmite ca parametru variadic la buildBlock. Dacă între expresii apare if, compilatorul apelează buildOptional sau buildEither pentru ramificare. Pentru bucle for-in se apelează buildArray. Astfel, codul obișnuit Swift este transformat într-un lanț de apeluri care construiesc valoarea finală.
Fiecare result builder definește un set de metode statice pe care compilatorul le apelează în timpul transformării. Metodele principale:
| Metodă | Scop | Când este apelată |
|---|---|---|
| buildBlock | Combină o secvență de expresii | Pentru fiecare bloc fără ramificare |
| buildOptional | Procesează if fără else | La prezența if fără else |
| buildEither(first:) | Prima ramură a if-else | La if cu else |
| buildEither(second:) | A doua ramură a if-else | La if cu else |
| buildArray | Procesează bucla for-in | La prezența for-in |
| buildExpression | Transformă o expresie individuală | Pentru fiecare expresie înainte de a o trimite la buildBlock |
| buildFinalResult | Transformarea finală | Înainte de returnarea din closure |
Implementarea minimă necesită doar buildBlock cu parametri variadic — acest lucru este suficient pentru blocuri fără ramificare. Adăugarea buildOptional și buildEither activează suportul pentru construcții condiționale, iar buildArray — pentru bucle. Conform Swift Documentation (2025), se recomandă implementarea tuturor metodelor pentru flexibilitate maximă a DSL-ului.
buildExpression permite primirea de expresii de diferite tipuri și transformarea lor la tipul comun al builderului. De exemplu, în @ViewBuilder, buildExpression primește Text, Image, Button și le aduce la tipul comun View.
Să considerăm skapande unui builder pentru construirea de șiruri HTML. Acest DSL va permite scrierea de HTML declarativ direct în 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()
}
}
användning builderului personalizat pentru generarea HTML:
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("Sidfot")
}
}
// Resultat: <div><p>Hello</p><p>World</p><p>Footer</p></div>
Conform articolului „Building Custom Result Builders in Swift” de pe Swift.org (2025), builderii personalizați sunt folosiți în biblioteci pentru construirea fișierelor de configurare, componentelor UI, mapării datelor și chiar a interogărilor de baze de date — oriunde este nevoie de o sintaxă declarativă cu suport pentru ramificare.
@ViewBuilder — este un result builder încorporat în SwiftUI, aplicat parametrului content al majorității containerelor: VStack, HStack, ZStack, Group, List și proprietății body în sine. Permite scrierea mai multor view-uri pe rânduri separate fără virgule și îmbrăcăminte.
@ViewBuilder implementează toate metodele result builder, inclusiv suportul pentru if-else, switch și for-in. Când condiția este îndeplinită, buildEither(first:) returnează un view; când nu — buildEither(second:) returnează altul. Ambele ramuri trebuie să returneze același tip, dar SwiftUI folosește AnyView intern sau ștergerea tipului prin ConditionalContent.
struct GreetingView: View {
let isLoggedIn: Bool
var body: some View {
VStack {
Image(systemName: "person.circle")
Text("Profil")
.font(.title)
if isLoggedIn {
Text("Välkommen tillbaka!")
.foregroundColor(.green)
} else {
Button("Logga in") { }
}
}
}
}
Fără @ViewBuilder, același cod ar necesita Group pentru fiecare secțiune condițională sau användning AnyView, ceea ce degradează performanța. @ViewBuilder alege automat cea mai eficientă reprezentare — ConditionalContent sau TupleView — pentru fiecare combinație.
Prima limitare — numărul maxim de expresii în buildBlock. Biblioteca standard Swift definește supraîncărcări ale buildBlock pentru 2–10 expresii. Dacă în bloc sunt mai mult de 10 expresii, compilatorul va genera o eroare. Soluția — grupare prin Group sau VStack pentru împărțirea în subblocuri.
A doua limitare — lipsa suportului pentru variabile și atribuiri în interiorul blocului builder. Nu se poate declara let x = 5 în interiorul @ViewBuilder. Toate expresiile trebuie să fie expresii care returnează valoarea tipului builderului. Pentru calcule intermediare, folosiți calcule în afara builderului sau buildExpression cu suport pentru diferite tipuri.
A treia limitare — dificultatea de depanare. Erorile de compilare în interiorul result builderului dau adesea mesaje confuze, mai ales la nepotrivirea tipurilor în ramurile if/else. Folosiți tipuri de returnare explicite și AnyView pentru depanare, deși ultimul reduce performanța. Conform Hacking with Swift (2025), sfatul practic — începeți cu un builder simplu fără ramificare și adăugați suportul pentru construcții condiționale treptat.
Întrebări frecvente
Result Builder — un atribut Swift care transformă o secvență de expresii într-o valoare rezultat prin metode statice. Permite skapande de DSL-uri declarative, cel mai cunoscut exemplu fiind @ViewBuilder în SwiftUI pentru construirea ierarhiei de view-uri fără cod imperativ.
Declarați o structură cu atributul @resultBuilder și implementați cel puțin metoda buildBlock. Pentru suportul condițiilor, adăugați buildOptional și buildEither, pentru bucle — buildArray. Folosiți atributul builderului înaintea parametrului closure din funcție.
Doar buildBlock este obligatoriu. Toate celelalte metode — buildOptional, buildEither, buildArray, buildExpression, buildFinalResult — sunt opționale și adaugă suport pentru construcțiile corespunzătoare. Cu cât mai multe metode sunt implementate, cu atât DSL-ul este mai flexibil.
@ViewBuilder — o implementare concretă a result builderului pentru protocolul View. Este definit în SwiftUI ca o structură cu atributul @resultBuilder, care oferă metodele buildBlock pentru diferite numere de view-uri (TupleView), buildEither pentru ConditionalContent și buildArray pentru ForEach.
Da, supraîncărcările standard ale buildBlock suportă până la 10 expresii. La depășire, folosiți containere imbricate (Group, VStack) pentru împărțirea în subblocuri. Un builder personalizat poate defini un buildBlock variadic fără limitare.
Concluzii
buildBlock, buildEither, buildOptional, buildArray în funcție de construcțiile de controlVi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också