@Binding — qué es, cómo funciona y ejemplos en SwiftUI

Autor: IT Sectr Publicado: 2026-06-19 Tiempo de lectura: 7 min

@Binding es un Property Wrapper en SwiftUI que crea una referencia a los datos que posee otro componente. Binding no almacena el valor por sí mismo — solo proporciona acceso a la fuente de verdad existente a través de la proyección $. Según la Documentación para Desarrolladores de Apple (2025), Binding proporciona una comunicación reactiva bidireccional entre una vista padre y una hija sin posesión directa de los datos. @Binding es el mecanismo clave para pasar estado mutable hacia abajo en la jerarquía.

Puntos clave

  • @Binding — Property Wrapper para crear una referencia al estado de la vista padre
  • Sin propiedad — Binding no almacena datos, solo proporciona acceso a la fuente de verdad
  • Proyección $ — $stateValue crea un Binding desde @State o @StateObject
  • Enlace bidireccional — los cambios en la vista hija se reflejan inmediatamente en la padre
  • Binding.constant — valor fijo para prototipado sin retroalimentación

¿Qué es @Binding en SwiftUI?

@Binding es un Property Wrapper que crea una conexión bidireccional entre una propiedad almacenada en la vista padre y un componente hijo. La principal diferencia entre Binding y @State: Binding no posee los datos. Solo lee y escribe valores a través de la fuente verdadera — @State, @StateObject u otro Binding en el padre. Sin Binding, las vistas hijas no podrían modificar el estado del ancestro sin callbacks o delegados.

Binding se implementa como una estructura con dos propiedades: wrappedValue (el valor actual) y projectedValue (el propio Binding, accesible mediante $). Cuando una vista hija cambia wrappedValue a través de Binding, SwiftUI transmite el cambio a la fuente de datos y redibuja todas las vistas dependientes. Esto ocurre sincrónicamente dentro del ciclo de actualización actual.

Una característica importante: @Binding no se limita a la transmisión de un solo nivel. Binding se puede pasar a través de varios niveles de jerarquía — cada componente hijo recibe una referencia a la misma fuente de datos. Un cambio en cualquier nivel desencadena una única actualización de todas las vistas enlazadas.

Cómo funciona el enlace bidireccional de Binding

El mecanismo de enlace bidireccional a través de @Binding se basa en las proyecciones de Property Wrappers. Cuando un padre declara @State var value: T, SwiftUI genera automáticamente la proyección $value de tipo Binding<T>. Al pasar $value a un componente hijo con @Binding var value: T, conectas ambas vistas a la misma celda de memoria. Cualquier escritura a través de Binding en la vista hija provoca un redibujado de ambos componentes.

swift
struct SliderContainer: View {
    @State private var value: Double = 0.5

    var body: some View {
        VStack {
            Text("Value: \(value)")
            SliderView(value: $value)
        }
    }
}

struct SliderView: View {
    @Binding var value: Double

    var body: some View {
        Slider(value: $value, in: 0...1)
    }
}

En el ejemplo, SliderContainer posee @State value, y SliderView recibe el Binding a través de $value. El Slider dentro de SliderView está vinculado a este Binding. Al arrastrar el control deslizante, Slider cambia el valor a través de Binding, lo que actualiza automáticamente @State en SliderContainer, y ambas vistas muestran el número actual. Toda la cadena funciona sin un solo callback o notificación.

Para crear un Binding desde @StateObject o @ObservedObject se usa la misma proyección: $object.property da Binding<PropertyType>. Esto permite pasar propiedades individuales de ObservableObject a vistas hijas sin pasar el objeto completo. Este enfoque proporciona un acoplamiento más preciso y evita redibujados innecesarios.

@Binding vs callbacks: qué elegir

Antes de SwiftUI, la forma estándar de pasar cambios hacia arriba en la jerarquía era mediante callbacks y delegados: el padre pasaba un cierre y el componente hijo lo invocaba al cambiar. @Binding ofrece una alternativa con menos código y una sintaxis más declarativa. En lugar de pasar un cierre de finalización, simplemente pasas $stateValue.

Criterio@BindingCallbacks
CódigoUna anotación + $Cierre + invocación
MultinivelAutomáticoCadena de cierres
PruebasBinding(value:constant)Cierres mock
LegibilidadAltaMedia
FlexibilidadSolo datosCualquier lógica

Usa @Binding cuando la vista hija solo necesite leer y modificar un valor. Si se requieren efectos secundarios al cambiar (validación, registro, solicitud de red), combina Binding con un callback: pasa Binding para los datos y un cierre para los eventos. Por ejemplo, un TextField puede enlazarse a un Binding, mientras que onChange activa la validación.

Patrones de uso de @Binding en proyectos

@Binding se utiliza en varios escenarios típicos. El primero — controles personalizados: interruptores, deslizadores, selectores de color y otros elementos interactivos aceptan Binding para sincronización bidireccional. El segundo — ventanas modales: la bandera de visualización de sheet se pasa como Binding, permitiendo que la vista hija se cierre mediante presentationMode o un ajuste directo.

El tercer patrón — formularios con separación. Si un formulario consta de muchos campos, cada campo se puede extraer en un componente separado que acepte un Binding para su valor. Esto simplifica las pruebas y la reutilización de campos en diferentes formularios. El componente padre sigue siendo el único propietario de todo el modelo del formulario.

swift
struct FormField: View {
    let title: String
    @Binding var text: String

    var body: some View {
        VStack(alignment: .leading) {
            Text(title).font(.caption)
            TextField("Enter \(title.lowercased())", text: $text)
                .textFieldStyle(.roundedBorder)
        }
    }
}

El componente FormField acepta un título y un Binding a una cadena. Muestra una etiqueta y un TextField vinculado al Binding pasado. Cualquier formulario puede usar FormField múltiples veces pasando $property para cada campo. Esto reduce la duplicación de marcado y centraliza el estilo de los campos de texto.

Creación de Bindings personalizados

SwiftUI permite crear Binding manualmente a través del inicializador Binding(get:set:). Esto es útil cuando se necesita agregar lógica al leer o escribir un valor. Por ejemplo, se puede crear un Binding que formatee un número antes de guardarlo, o un Binding que sincronice el valor con un servidor remoto en cada cambio.

swift
struct ValidatedField: View {
    @State private var email: String = ""

    var emailBinding: Binding<String> {
        .init(
            get: { email },
            set: { email = $0.lowercased().trimmingCharacters(in: .whitespaces) }
        )
    }

    var body: some View {
        TextField("Email", text: emailBinding)
    }
}

En el listado, el emailBinding personalizado convierte automáticamente el texto a minúsculas y elimina espacios en cada cambio. El TextField usa este Binding en lugar de enlazar directamente a $email. Este enfoque centraliza la validación y transformación de datos dentro del Binding sin saturar el código con manejadores onChange.

Errores y antipatrones con @Binding

El primer error y el más común es pasar un valor en lugar de un Binding. Si un componente hijo declara @Binding var text: String, y el padre pasa text (sin $), el compilador dará un error: Cannot convert value of type 'String' to expected argument type 'Binding<String>'. La solución — usar siempre el prefijo $ al pasar: $text.

El segundo error — Binding en datos de solo lectura. Si la vista hija solo necesita leer un valor, no uses @Binding — basta con un let simple o @State del padre. Binding implica la capacidad de escritura, y los permisos de modificación excesivos complican la depuración y violan el principio de privilegio mínimo.

El tercer problema — Binding.constant en producción. Binding.constant(value) crea un enlace ficticio sin retroalimentación — los cambios se ignoran. Usa constant solo para prototipado y previsualizaciones (Xcode Previews), pero nunca en código real. Para pruebas, usa Binding(get:set:) con comportamiento controlado.

Preguntas frecuentes

¿Cuál es la diferencia entre @Binding y @State?

@State posee los datos y gestiona su almacenamiento en el montón. @Binding solo hace referencia al estado existente sin posesión. @State siempre es privado, @Binding es un parámetro de entrada de la vista hija.

¿Se puede crear un Binding sin @State?

Sí, a través del inicializador Binding(get:set:) o Binding.constant(value). También se puede obtener un Binding desde @StateObject mediante la proyección $object.$property y desde Publisher mediante Binding(get:set:) dentro de Subscribe.

¿Cómo pasar Binding a través de múltiples niveles de anidamiento?

@Binding se pasa por cadena: cada componente intermedio declara @Binding y lo pasa hacia adelante mediante $. Todos los niveles hacen referencia a la misma fuente de datos en la vista raíz.

¿Por qué Binding.constant no actualiza la interfaz?

Binding.constant crea una envoltura muda — el setter ignora los nuevos valores. Está destinado solo para prototipado y Previews de SwiftUI donde no se requiere retroalimentación del componente hijo.

¿Puede @Binding ser opcional?

Sí, Binding<T?> es compatible. Si pasas Binding<String?>, la vista hija podrá establecer nil. Esto es conveniente para campos de formulario opcionales o estados con posibilidad de reinicio.

Resumen

  • @Binding — Property Wrapper para enlace bidireccional con datos de la vista padre
  • No posee datos — solo proporciona acceso a la fuente de verdad
  • Proyección $ convierte @State, @StateObject en Binding para pasar a vistas hijas
  • Binding personalizado creado mediante Binding(get:set:) con lógica adicional
  • Binding.constant — solo para previsualizaciones y prototipos
  • Transmisión multinivel — Binding atraviesa cualquier profundidad de anidamiento
  • Alternativa a callbacks — forma declarativa de modificar el estado desde componentes hijos

Desarrollaremos 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.

Discutir el proyecto

Lea también