Result Builder es un atributo de Swift implementado a través del protocolo @resultBuilder que transforma una secuencia de expresiones en un valor compuesto. El compilador convierte bloques de código con construcciones de control if, for, switch en llamadas a métodos estáticos del builder — buildBlock, buildEither, buildArray. Según la propuesta Swift Evolution SE-0289 (2022), los result builders permiten crear DSL declarativos dentro de Swift sin analizadores externos. El ejemplo más conocido es @ViewBuilder en SwiftUI, donde el cuerpo de la vista se construye a partir de elementos condicionales y cíclicos en un estilo declarativo.
Puntos clave
TupleViewif/else, switch, for-in a través de los métodos buildOptional, buildEither, buildArrayResult Builder (anteriormente conocido como function builders) es un mecanismo de Swift que permite convertir una secuencia de expresiones separadas por saltos de línea en un único valor. Se declara mediante el atributo @resultBuilder aplicado a una estructura que implementa métodos de transformación estáticos.
Antes de los result builders, la sintaxis declarativa del body de SwiftUI era imposible. En lugar de una lista compacta de vistas, los desarrolladores tenían que escribir llamadas a TupleView manualmente. Result Builder envuelve automáticamente cada expresión, soporta ramificaciones y bucles, ocultando la complejidad de la composición al desarrollador.
Según Swift Evolution SE-0289, aceptada en 2022, el result builder es una evolución de la idea de function builders (SE-0258, Swift 5.1). Cambios clave: renombrar de @_functionBuilder a @resultBuilder y extensión a parámetros de funciones, permitiendo usar builders para cualquier argumento closure, no solo para cuerpos de vista.
Usa result builders cuando necesites proporcionar a los usuarios de tu biblioteca una sintaxis declarativa para construir estructuras complejas — configuraciones, consultas, componentes de UI — sin escribir código ensamblador imperativo.
El compilador de Swift transforma cada bloque de código marcado con @resultBuilder en una secuencia de llamadas a métodos estáticos del builder. Veamos un builder simple que concatena cadenas:
@resultBuilder
struct StringBuilder {
static func buildBlock(_ parts: String...) -> String {
parts.joined(separator: " ")
}
}
Usando este builder — cada cadena en una línea separada se concatena con un espacio:
@StringBuilder
func greeting() -> String {
"Hello"
"World"
"from"
"Swift"
}
// El compilador transforma esto en:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// Resultado: "Hello World from Swift"
El compilador agrupa expresiones consecutivas y las pasa como parámetros variádicos a buildBlock. Si aparece un if entre expresiones, el compilador llama a buildOptional o buildEither para la ramificación. Para bucles for-in llama a buildArray. Así, el código Swift normal se transforma en una cadena de llamadas que construyen el valor final.
Cada result builder define un conjunto de métodos estáticos que el compilador llama durante la transformación. Los métodos principales:
| Método | Propósito | Cuándo se llama |
|---|---|---|
| buildBlock | Combina una secuencia de expresiones | Para cada bloque sin ramificación |
| buildOptional | Maneja if sin else | Cuando hay if sin else |
| buildEither(first:) | Primera rama de if-else | Para if con else |
| buildEither(second:) | Segunda rama de if-else | Para if con else |
| buildArray | Maneja bucles for-in | Cuando hay for-in |
| buildExpression | Transforma expresiones individuales | Para cada expresión antes de pasarla a buildBlock |
| buildFinalResult | Transformación final | Antes de retornar del closure |
Una implementación mínima requiere solo buildBlock con parámetros variádicos — esto es suficiente para bloques sin ramificación. Agregar buildOptional y buildEither incluye soporte para construcciones condicionales, y buildArray para bucles. Según la Documentación de Swift (2025), se recomienda implementar todos los métodos para máxima flexibilidad del DSL.
buildExpression permite aceptar expresiones de diferentes tipos y convertirlas a un tipo único del builder. Por ejemplo, en @ViewBuilder, buildExpression acepta Text, Image, Button y los convierte al tipo común View.
Veamos la creación de un builder para construir cadenas HTML. Este DSL permitirá escribir HTML declarativo directamente en 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()
}
}
Usando el builder personalizado para generar 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("Pie de página")
}
}
// Resultado: <div><p>Hello</p><p>World</p><p>Footer</p></div>
Según el artículo “Building Custom Result Builders in Swift” de Swift.org (2025), los builders personalizados se usan en bibliotecas para construir archivos de configuración, componentes de UI, mapeo de datos e incluso consultas a bases de datos — en cualquier lugar donde se necesite una sintaxis declarativa con soporte de ramificaciones.
@ViewBuilder es un result builder integrado en SwiftUI que se aplica al parámetro content de la mayoría de las vistas contenedoras: VStack, HStack, ZStack, Group, List y la propiedad body misma. Permite escribir múltiples vistas en líneas separadas sin comas ni envoltorios.
@ViewBuilder implementa todos los métodos de result builder, incluyendo soporte para if-else, switch y for-in. Cuando una condición se cumple, buildEither(first:) devuelve una vista; cuando no, buildEither(second:) devuelve otra. Ambas ramas deben devolver el mismo tipo, pero SwiftUI usa AnyView internamente o borrado de tipo a través de ConditionalContent.
struct GreetingView: View {
let isLoggedIn: Bool
var body: some View {
VStack {
Image(systemName: "person.circle")
Text("Perfil")
.font(.title)
if isLoggedIn {
Text("¡Bienvenido de nuevo!")
.foregroundColor(.green)
} else {
Button("Iniciar sesión") { }
}
}
}
}
Sin @ViewBuilder, el mismo código requeriría Group para cada sección condicional o usar AnyView, lo que perjudica el rendimiento. @ViewBuilder selecciona automáticamente la representación más eficiente — ConditionalContent o TupleView — para cada combinación.
La primera limitación es el número máximo de expresiones en buildBlock. La biblioteca estándar de Swift define sobrecargas de buildBlock para 2–10 expresiones. Si un bloque tiene más de 10 expresiones, el compilador generará un error. La solución es agrupar mediante Group o VStack para dividir en sub-bloques.
La segunda limitación es la falta de soporte para variables y asignaciones dentro del bloque del builder. No se puede declarar let x = 5 dentro de @ViewBuilder. Todas las expresiones deben ser expresiones que devuelvan un valor del tipo del builder. Para cálculos intermedios, usa cálculos fuera del builder o buildExpression con soporte para diferentes tipos.
La tercera limitación es la complejidad de depuración. Los errores de compilación dentro de un result builder a menudo producen mensajes confusos, especialmente cuando los tipos no coinciden en las ramas if/else. Usa tipos de retorno explícitos y AnyView para depuración, aunque esto último reduce el rendimiento. Según Hacking with Swift (2025), un consejo práctico es comenzar con un builder simple sin ramificaciones y agregar soporte para construcciones condicionales gradualmente.
Preguntas frecuentes
Result Builder es un atributo de Swift que transforma una secuencia de expresiones en un valor resultante a través de métodos estáticos. Permite crear DSL declarativos, el ejemplo más conocido es @ViewBuilder en SwiftUI para construir jerarquías de vista sin código imperativo.
Declara una estructura con el atributo @resultBuilder e implementa al menos el método buildBlock. Para soportar condiciones, agrega buildOptional y buildEither; para bucles, agrega buildArray. Usa el atributo del builder antes del parámetro closure en una función.
Solo buildBlock es obligatorio. Todos los demás métodos — buildOptional, buildEither, buildArray, buildExpression, buildFinalResult — son opcionales y añaden soporte para las construcciones correspondientes. Cuantos más métodos se implementen, más flexible será el DSL.
@ViewBuilder es una implementación concreta del result builder para el protocolo View. Está definido en SwiftUI como una estructura con el atributo @resultBuilder, que proporciona métodos buildBlock para diferentes cantidades de vistas (TupleView), buildEither para ConditionalContent y buildArray para ForEach.
Sí, las sobrecargas estándar de buildBlock soportan hasta 10 expresiones. Al exceder este límite, usa contenedores anidados (Group, VStack) para dividir en sub-bloques. Un builder personalizado puede definir un buildBlock variádico sin limitación.
Resumen
buildBlock, buildEither, buildOptional, buildArray según las construcciones de controlDesarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también