@Binding — cos'è, come funziona ed esempi in SwiftUI

Autore: IT Sectr Pubblicato: 2026-06-19 Tempo di lettura: 7 min

@Binding è un Property Wrapper in SwiftUI che crea un riferimento a dati posseduti da un altro componente. Binding non memorizza il valore da solo — fornisce solo l'accesso alla fonte di verità esistente attraverso la proiezione $. Secondo la Documentazione Sviluppatori Apple (2025), Binding fornisce una comunicazione reattiva bidirezionale tra la vista padre e quella figlia senza possesso diretto dei dati. @Binding è il meccanismo chiave per passare lo stato mutabile verso il basso nella gerarchia.

Punti chiave

  • @Binding — Property Wrapper per creare un riferimento allo stato della vista padre
  • Senza proprietà — Binding non memorizza dati, fornisce solo accesso alla fonte di verità
  • Proiezione $ — $stateValue crea un Binding da @State o @StateObject
  • Binding bidirezionale — le modifiche nella vista figlia si riflettono immediatamente nel padre
  • Binding.constant — valore fisso per prototipazione senza feedback

Cos'è @Binding in SwiftUI?

@Binding è un Property Wrapper che crea una connessione bidirezionale tra una proprietà memorizzata nella vista padre e un componente figlio. La differenza principale tra Binding e @State: Binding non possiede i dati. Legge e scrive valori solo attraverso la fonte vera — @State, @StateObject o un altro Binding nel padre. Senza Binding, le viste figlie non potrebbero modificare lo stato dell'antenato senza callback o delegati.

Binding è implementato come una struttura con due proprietà: wrappedValue (il valore corrente) e projectedValue (il Binding stesso, accessibile tramite $). Quando una vista figlia modifica wrappedValue attraverso Binding, SwiftUI trasmette la modifica alla fonte dati e ridisegna tutte le viste dipendenti. Questo avviene in modo sincrono all'interno del ciclo di aggiornamento corrente.

Una caratteristica importante: @Binding non si limita al passaggio a un singolo livello. Binding può essere passato attraverso più livelli di gerarchia — ogni componente figlio riceve un riferimento alla stessa fonte dati. Una modifica a qualsiasi livello attiva un unico aggiornamento di tutte le viste legate.

Come funziona il binding bidirezionale di Binding

Il meccanismo di binding bidirezionale attraverso @Binding si basa sulle proiezioni di Property Wrapper. Quando un padre dichiara @State var value: T, SwiftUI genera automaticamente la proiezione $value di tipo Binding<T>. Passando $value a un componente figlio con @Binding var value: T, si collegano entrambe le viste alla stessa cella di memoria. Qualsiasi scrittura attraverso Binding nella vista figlia attiva un ridisegno di entrambi i componenti.

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

Nell'esempio, SliderContainer possiede @State value, e SliderView riceve il Binding attraverso $value. Lo Slider all'interno di SliderView è legato a questo Binding. Trascinando il cursore, Slider modifica il valore attraverso Binding, che aggiorna automaticamente @State in SliderContainer, ed entrambe le viste visualizzano il numero corrente. L'intera catena funziona senza un singolo callback o notifica.

Per creare un Binding da @StateObject o @ObservedObject, si usa la stessa proiezione: $object.property fornisce Binding<PropertyType>. Ciò consente di passare proprietà individuali di ObservableObject alle viste figlie senza passare l'intero oggetto. Questo approccio fornisce un accoppiamento più stretto e previene ridisegni non necessari.

@Binding vs callback: cosa scegliere

Prima di SwiftUI, il modo standard per passare le modifiche verso l'alto nella gerarchia era attraverso callback e delegati: il padre passava una closure, il componente figlio la invocava al momento della modifica. @Binding offre un'alternativa con meno codice e una sintassi più dichiarativa. Invece di passare una closure di completamento, si passa semplicemente $stateValue.

Criterio@BindingCallback
CodiceUn'annotazione + $Closure + invocazione
MultilivelloAutomaticoCatena di closure
TestBinding(value:constant)Closure mock
LeggibilitàAltaMedia
FlessibilitàSolo datiQualsiasi logica

Usa @Binding quando la vista figlia ha solo bisogno di leggere e modificare un valore. Se sono necessari effetti collaterali al momento della modifica (validazione, registrazione, richiesta di rete), combina Binding con un callback: passa Binding per i dati e una closure per gli eventi. Ad esempio, un TextField può essere legato a un Binding, mentre onChange attiva la validazione.

Pattern di utilizzo di @Binding nei progetti

@Binding viene utilizzato in diversi scenari tipici. Il primo — controlli personalizzati: interruttori, cursori, selettori di colore e altri elementi interattivi accettano Binding per la sincronizzazione bidirezionale. Il secondo — finestre modali: il flag di visualizzazione del sheet viene passato come Binding, consentendo alla vista figlia di chiudersi tramite presentationMode o impostazione diretta.

Il terzo pattern — moduli con separazione. Se un modulo è composto da molti campi, ogni campo può essere estratto in un componente separato che accetta un Binding per il suo valore. Ciò semplifica il test e il riutilizzo dei campi tra diversi moduli. Il componente padre rimane l'unico proprietario dell'intero modello del modulo.

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

Il componente FormField accetta un titolo e un Binding a una stringa. Mostra un'etichetta e un TextField legato al Binding passato. Qualsiasi modulo può usare FormField più volte passando $property per ogni campo. Ciò riduce la duplicazione del markup e centralizza la stilizzazione dei campi di testo.

Creazione di Binding personalizzati

SwiftUI consente di creare Binding manualmente tramite l'inizializzatore Binding(get:set:). Ciò è utile quando è necessario aggiungere logica alla lettura o scrittura di un valore. Ad esempio, si può creare un Binding che formatta un numero prima di salvarlo, o un Binding che sincronizza il valore con un server remoto a ogni modifica.

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

Nel listato, il emailBinding personalizzato converte automaticamente il testo in minuscolo e rimuove gli spazi a ogni modifica. Il TextField usa questo Binding invece di legarsi direttamente a $email. Questo approccio centralizza la validazione e la trasformazione dei dati all'interno del Binding senza ingombrare il codice con gestori onChange.

Errori e anti-pattern con @Binding

Il primo e più comune errore è passare un valore invece di un Binding. Se un componente figlio dichiara @Binding var text: String, e il padre passa text (senza $), il compilatore darà un errore: Cannot convert value of type 'String' to expected argument type 'Binding<String>'. La soluzione — usa sempre il prefisso $ quando passi: $text.

Il secondo errore — Binding su dati di sola lettura. Se la vista figlia ha solo bisogno di leggere un valore, non usare @Binding — basta un semplice let o @State dal padre. Binding implica la capacità di scrittura, e permessi di modifica eccessivi complicano il debug e violano il principio del minimo privilegio.

Il terzo problema — Binding.constant in produzione. Binding.constant(value) crea un legame fittizio senza feedback — le modifiche vengono ignorate. Usa constant solo per prototipazione e anteprime (Xcode Previews), ma mai nel codice reale. Per i test, usa Binding(get:set:) con comportamento controllato.

Domande frequenti

Qual è la differenza tra @Binding e @State?

@State possiede i dati e gestisce la loro memorizzazione nell'heap. @Binding riferisce solo lo stato esistente senza possesso. @State è sempre privato, @Binding è un parametro di input della vista figlia.

Si può creare un Binding senza @State?

Sì, tramite l'inizializzatore Binding(get:set:) o Binding.constant(value). Binding può anche essere ottenuto da @StateObject attraverso la proiezione $object.$property e da Publisher tramite Binding(get:set:) all'interno di Subscribe.

Come passare Binding attraverso più livelli di annidamento?

@Binding viene passato a catena: ogni componente intermedio dichiara @Binding e lo passa oltre tramite $. Tutti i livelli fanno riferimento alla stessa fonte dati nella vista radice.

Perché Binding.constant non aggiorna l'interfaccia?

Binding.constant crea un involucro muto — il setter ignora i nuovi valori. È destinato solo alla prototipazione e alle Previews SwiftUI dove non è richiesto feedback dal componente figlio.

@Binding può essere opzionale?

Sì, Binding<T?> è supportato. Se passi Binding<String?>, la vista figlia potrà impostare nil. Ciò è comodo per campi modulo opzionali o stati con possibilità di reset.

Riepilogo

  • @Binding — Property Wrapper per binding bidirezionale con i dati della vista padre
  • Non possiede dati — fornisce solo accesso alla fonte di verità
  • Proiezione $ trasforma @State, @StateObject in Binding da passare alle viste figlie
  • Binding personalizzato creato tramite Binding(get:set:) con logica aggiuntiva
  • Binding.constant — solo per anteprime e prototipi
  • Passaggio multilivello — Binding attraversa qualsiasi profondità di annidamento
  • Alternativa ai callback — modo dichiarativo per modificare lo stato dai componenti figli

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche