Dominando Swift resultBuilder: como o Builder Pattern evoluiu para a sintaxe da linguagem
Você pensou nisso quando viu SwiftUI pela primeira vez?
“Espera, como listar várias views dentro de VStack { Text("A"); Text("B") } pode funcionar?”
À primeira vista, parece mágica. Não há ponto e vírgula, vírgula nem return, mas tudo é montado automaticamente.
A identidade dessa mágica é o Swift resultBuilder.
Em resumo, resultBuilder transforma o Builder Pattern que antes implementávamos manualmente como padrão de projeto em um recurso da linguagem, permitindo que o compilador escreva esse código por nós. Ele substitui o código repetitivo de montar objetos passo a passo por uma única sintaxe de bloco com chaves.
O que era mesmo o Builder Pattern?
Vamos relembrar rapidamente o Builder Pattern tradicional.
O Builder Pattern cria um objeto complexo adicionando suas partes uma a uma, em vez de construir tudo de uma vez.
let request = URLRequestBuilder()
.setURL("https://naver.com")
.setMethod("GET")
.addHeader("Accept", "application/json")
.build()
A montagem é feita encadeando métodos assim.
É fácil de ler, mas há desvantagens. Você precisa criar manualmente a classe Builder toda vez e, se esquecer build(), o objeto não é concluído.
Ou seja, o desenvolvedor precisava gerenciar diretamente a lógica de montagem.
O resultBuilder entrega exatamente essa responsabilidade ao compilador.
Como o resultBuilder funciona?
A ideia central é simples.
O compilador passa, um por um, os valores listados em um bloco de chaves para funções de regra predefinidas e os combina em um único resultado final.
Essas funções de regra são métodos estáticos como buildBlock.
Por exemplo, vamos criar um builder bem simples que reúne strings.
@resultBuilder
struct StringBuilder {
static func buildBlock(_ parts: String...) -> String {
parts.joined(separator: " ")
}
}
@StringBuilder
func greeting() -> String {
"Olá"
"resultBuilder"
"sou eu"
}
// Resultado: "Olá resultBuilder sou eu"
Dentro da função greeting(), apenas listamos três strings em três linhas, certo?
O compilador substituiu essas três linhas por uma chamada a buildBlock("안녕하세요", "resultBuilder", "입니다").
A sintaxe passou a escrever o código de montagem que antes fazíamos manualmente.
Como condicionais e loops são tratados?
Às vezes queremos usar if ou for dentro de um bloco, algo comum também no SwiftUI.
Para isso, o resultBuilder oferece métodos de regra adicionais.
Veja os principais métodos resumidos em uma tabela.
| Método | Quando é chamado? |
|---|---|
buildBlock |
Ao combinar vários valores do bloco em um só |
buildOptional |
Quando existe apenas if e não existe else |
buildEither(first:) / buildEither(second:) |
Ao processar o ramo if-else |
buildArray |
Ao reunir resultados repetidos de for |
buildExpression |
Ao transformar primeiro a expressão de cada linha |
Os métodos implementados determinam quais construções de sintaxe o builder permite.
Sem criar buildOptional, não é possível usar if dentro do bloco.
Por isso, o @ViewBuilder do SwiftUI implementa quase todos esses métodos. Assim, condicionais e loops podem ser usados naturalmente dentro dos blocos de views.
O que gostei e os cuidados depois de usar na prática
Já usei resultBuilder em pequenos geradores de HTML e na construção de dados de teste.
O melhor foi que o local da chamada fica declarativo e elegante. Como o processo de montagem não aparece, quem lê consegue se concentrar em “o que criar”.
Mas também há cuidados claros.
- As mensagens de erro de compilação costumam ser pouco úteis. Se os tipos não corresponderem dentro de um bloco, o erro pode apontar para um local totalmente errado.
- O uso excessivo pode piorar as coisas. Se você só precisa criar um array simples, é melhor usar um literal de array.
- Durante a depuração, é difícil rastrear qual método
build...foi realmente chamado.
Por isso, recomendo usá-lo apenas com estruturas montadas repetidamente, como uma DSL (Domain-Specific Language, linguagem específica de domínio). SwiftUI, definições de rotas no servidor e query builders são bons exemplos.
Uma dica para o desenvolvimento iOS: na maioria dos casos, é mais importante entender e usar bem @ViewBuilder do que criar @resultBuilder diretamente.
Resumo
Em resumo, resultBuilder é uma evolução do Builder Pattern que a linguagem absorveu do código que antes escrevíamos manualmente.
Quando você entende que o compilador monta tudo o que é listado entre chaves, fica natural compreender por que o SwiftUI tem esse formato.
Digite o código do exemplo de hoje você mesmo. Ele é assimilado muito mais rápido do que apenas lendo.

