Result Builder — co to jest, składnia i zastosowanie

Autor: IT Sectr Opublikowano: 2026-06-20 Czas czytania: 8 min

Result Builder — atrybut Swifta, implementowany przez protokół @resultBuilder, który przekształca sekwencję wyrażeń w wartość złożoną. Kompilator przekształca bloki kodu z konstrukcjami sterującymi if, for, switch w wywołania metod statycznych buildera — buildBlock, buildEither, buildArray. Według Swift Evolution proposal SE-0289 (2022), result buildery pozwalają tworzyć deklaratywne DSL w Swift bez zewnętrznych parserów. Najbardziej znany przykład — @ViewBuilder w SwiftUI, gdzie ciało widoku budowane jest z elementów warunkowych i cyklicznych w deklaratywnym stylu.

Najważniejsze

  • Result Builder — atrybut Swifta, przekształcający sekwencję wyrażeń w wartość wynikową przez statyczne metody buildera
  • @ViewBuilder — najbardziej znany przykład: przekształca wiele widoków w jedną złożoną reprezentację TupleView
  • Konstrukcje sterujące — builder obsługuje if/else, switch, for-in przez metody buildOptional, buildEither, buildArray
  • Niestandardowe buildery można tworzyć dla własnych DSL — HTML, CSS, konfiguracje, zapytania
  • Swift 5.4 rozszerzył wsparcie dla result builderów na funkcje i parametry funkcji — teraz builder może być zastosowany do argumentu closure

Czym jest Result Builder?

Result Builder (wcześniej znany jako function builders) — to mechanizm Swifta, który pozwala przekształcić sekwencję wyrażeń oddzielonych znakiem nowej linii w pojedynczą wartość. Jest deklarowany za pomocą atrybutu @resultBuilder zastosowanego do struktury, która implementuje statyczne metody transformacji.

Przed pojawieniem się result builderów deklaratywna składnia SwiftUI body była niemożliwa. Zamiast zwięzłej listy widoków programista musiałby ręcznie pisać wywołania TupleView. Result Builder automatycznie opakowuje każde wyrażenie, obsługuje rozgałęzienia i pętle, ukrywając złożoność kompozycji przed programistą.

Według Swift Evolution SE-0289, przyjętego w 2022 roku, result builder to rozwinięcie idei function builders (SE-0258, Swift 5.1). Główne zmiany: przemianowanie z @_functionBuilder na @resultBuilder i rozszerzenie na parametry funkcji, co pozwoliło używać builderów dla dowolnych argumentów closure, a nie tylko dla ciała widoku.

Używaj result builderów, gdy chcesz udostępnić użytkownikom swojej biblioteki deklaratywną składnię do budowania złożonych struktur — konfiguracji, zapytań, komponentów UI — bez pisania imperatywnego kodu składania.

Jak działa Result Builder

Kompilator Swifta przekształca każdy blok kodu oznaczony @resultBuilder w sekwencję wywołań statycznych metod buildera. Rozważmy najprostszy builder, który łączy ciągi znaków:

swift
@resultBuilder
struct StringBuilder {
    static func buildBlock(_ parts: String...) -> String {
        parts.joined(separator: " ")
    }
}

Użycie tego buildera — każdy wiersz w osobnej linii łączony jest spacją:

swift
@StringBuilder
func greeting() -> String {
    "Hello"
    "World"
    "from"
    "Swift"
}
// Kompilator przekształca to na:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// Wynik: "Hello World from Swift"

Kompilator grupuje kolejne wyrażenia i przekazuje je jako parametr variadic do buildBlock. Jeśli między wyrażeniami występuje if, kompilator wywołuje buildOptional lub buildEither dla rozgałęzienia. Dla pętli for-in wywoływane jest buildArray. W ten sposób zwykły kod Swifta przekształcany jest w łańcuch wywołań konstruujących końcową wartość.

Metody buildera: buildBlock, buildOptional, buildEither

Każdy result builder definiuje zestaw metod statycznych, które kompilator wywołuje podczas transformacji. Podstawowe metody:

MetodaPrzeznaczenieKiedy wywoływana
buildBlockŁączy sekwencję wyrażeńDla każdego bloku bez rozgałęzień
buildOptionalObsługuje if bez elsePrzy wystąpieniu if bez else
buildEither(first:)Pierwsza gałąź if-elsePrzy if z else
buildEither(second:)Druga gałąź if-elsePrzy if z else
buildArrayObsługuje pętlę for-inPrzy wystąpieniu for-in
buildExpressionPrzekształca pojedyncze wyrażenieDla każdego wyrażenia przed przekazaniem do buildBlock
buildFinalResultKońcowe przekształceniePrzed zwróceniem z closure

Minimalna implementacja wymaga tylko buildBlock z parametrami variadic — to wystarcza dla bloków bez rozgałęzień. Dodanie buildOptional i buildEither włącza obsługę konstrukcji warunkowych, a buildArray — pętli. Według Swift Documentation (2025), zaleca się implementację wszystkich metod dla maksymalnej elastyczności DSL.

buildExpression pozwala przyjmować wyrażenia różnych typów i przekształcać je do wspólnego typu buildera. Na przykład w @ViewBuilder buildExpression przyjmuje Text, Image, Button i sprowadza je do wspólnego typu View.

Tworzenie własnego Result Builder

Rozważmy stworzenie buildera do budowania ciągów HTML. Ten DSL pozwoli pisać deklaratywny HTML bezpośrednio w Swifcie:

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()
    }
}

Użycie niestandardowego buildera do generowania HTML:

swift
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("Stopka")
    }
}
// Wynik: <div><p>Hello</p><p>World</p><p>Footer</p></div>

Według artykułu „Building Custom Result Builders in Swift” ze Swift.org (2025), niestandardowe buildery są używane w bibliotekach do budowania plików konfiguracyjnych, komponentów UI, mapowania danych, a nawet zapytań do bazy danych — wszędzie tam, gdzie potrzebna jest deklaratywna składnia z obsługą rozgałęzień.

@ViewBuilder w SwiftUI

@ViewBuilder — to result builder wbudowany w SwiftUI, stosowany do parametru content większości kontenerów: VStack, HStack, ZStack, Group, List oraz samej właściwości body. Pozwala pisać wiele widoków w osobnych wierszach bez przecinków i opakowań.

@ViewBuilder implementuje wszystkie metody result buildera, w tym obsługę if-else, switch i for-in. Gdy warunek jest spełniony, buildEither(first:) zwraca jeden widok; gdy nie — buildEither(second:) zwraca inny. Obie gałęzie muszą zwracać ten sam typ, ale SwiftUI używa AnyView wewnętrznie lub zacierania typu przez ConditionalContent.

swift
struct GreetingView: View {
    let isLoggedIn: Bool

    var body: some View {
        VStack {
            Image(systemName: "person.circle")
            Text("Profil")
                .font(.title)

            if isLoggedIn {
                Text("Witaj ponownie!")
                    .foregroundColor(.green)
            } else {
                Button("Zaloguj się") { }
            }
        }
    }
}

Bez @ViewBuilder ten sam kod wymagałby Group dla każdej sekcji warunkowej lub użycia AnyView, co pogarsza wydajność. @ViewBuilder automatycznie wybiera najefektywniejszą reprezentację — ConditionalContent lub TupleView — dla każdej kombinacji.

Ograniczenia Result Builder

Pierwsze ograniczenie — maksymalna liczba wyrażeń w buildBlock. Standardowa biblioteka Swifta definiuje przeciążenia buildBlock dla 2–10 wyrażeń. Jeśli w bloku jest więcej niż 10 wyrażeń, kompilator zgłosi błąd. Rozwiązanie — grupowanie przez Group lub VStack w celu podziału na podbloki.

Drugie ograniczenie — brak wsparcia dla zmiennych i przypisań wewnątrz bloku buildera. Nie można zadeklarować let x = 5 wewnątrz @ViewBuilder. Wszystkie wyrażenia muszą być wyrażeniami zwracającymi wartość typu buildera. Do obliczeń pośrednich używaj obliczeń poza builderem lub buildExpression z obsługą różnych typów.

Trzecie ograniczenie — trudność debugowania. Błędy kompilacji wewnątrz result buildera często dają mylące komunikaty, szczególnie przy niezgodności typów w gałęziach if/else. Używaj jawnych typów zwracanych i AnyView do debugowania, choć ten ostatni obniża wydajność. Według Hacking with Swift (2025), praktyczna rada — zaczynaj od prostego buildera bez rozgałęzień i stopniowo dodawaj obsługę konstrukcji warunkowych.

Często zadawane pytania

Czym jest Result Builder w Swift?

Result Builder — atrybut Swifta, przekształcający sekwencję wyrażeń w wartość wynikową przez statyczne metody. Pozwala tworzyć deklaratywne DSL, najbardziej znany przykład — @ViewBuilder w SwiftUI do budowania hierarchii widoków bez kodu imperatywnego.

Jak stworzyć własny Result Builder?

Zadeklaruj strukturę z atrybutem @resultBuilder i zaimplementuj co najmniej metodę buildBlock. Aby obsługiwać warunki, dodaj buildOptional i buildEither, dla pętli — buildArray. Użyj atrybutu buildera przed parametrem closure w funkcji.

Które metody są obowiązkowe dla Result Builder?

Obowiązkowy jest tylko buildBlock. Wszystkie pozostałe metody — buildOptional, buildEither, buildArray, buildExpression, buildFinalResult — są opcjonalne i dodają obsługę odpowiednich konstrukcji. Im więcej metod zaimplementowano, tym elastyczniejszy DSL.

Dlaczego @ViewBuilder jest Result Builderem?

@ViewBuilder — to konkretna implementacja result buildera dla protokołu View. Jest zdefiniowany w SwiftUI jako struktura z atrybutem @resultBuilder, dostarczająca metody buildBlock dla różnych liczb widoków (TupleView), buildEither dla ConditionalContent i buildArray dla ForEach.

Czy jest ograniczenie liczby wyrażeń w builderze?

Tak, standardowe przeciążenia buildBlock obsługują do 10 wyrażeń. Po przekroczeniu używaj zagnieżdżonych kontenerów (Group, VStack) do podziału na podbloki. Niestandardowy builder może zdefiniować variadic buildBlock bez ograniczenia.

Podsumowanie

  • Result Builder — atrybut Swifta, przekształcający sekwencję wyrażeń w pojedynczą wartość przez statyczne metody buildera
  • Kompilator zastępuje blok kodu wywołaniami buildBlock, buildEither, buildOptional, buildArray w zależności od konstrukcji sterujących
  • @ViewBuilder — wbudowany result builder SwiftUI, umożliwiający pisanie deklaratywnego kodu hierarchii widoków z obsługą warunków i pętli
  • Niestandardowe buildery są używane do budowania DSL: HTML, konfiguracji, zapytań — dowolnej struktury zyskującej na deklaratywnej składni
  • Ograniczenia: maks. 10 wyrażeń w buildBlock, brak możliwości deklarowania zmiennych, mylące błędy kompilacji przy niezgodności typów
  • Swift 5.4+ — buildery można stosować do parametrów funkcji, co rozszerza scenariusze użycia poza ciało widoku

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również