@Binding är en Property Wrapper i SwiftUI som skapar en referens till data som ägs av en annan komponent. Binding lagrar inte värdet självständigt — det ger bara tillgång till den befintliga sanningskällan genom $-projektionen. Enligt Apple Developer Documentation (2025) tillhandahåller Binding en reaktiv tvåvägsförbindelse mellan förälder- och barnvyn utan direkt ägande av data. @Binding är den viktigaste mekanismen för att skicka föränderligt tillstånd nedåt i hierarkin.
Huvudpunkter
@Binding är en Property Wrapper som skapar en tvåvägsförbindelse mellan en egenskap lagrad i föräldervyn och en barnkomponent. Huvudskillnaden mellan Binding och @State: Binding äger inte data. Det läser och skriver bara värdet via den verkliga källan — @State, @StateObject eller en annan Binding i föräldern. Utan Binding skulle barnvyn inte kunna ändra förfaderns tillstånd utan callbacks eller delegater.
Binding är implementerad som en struktur med två egenskaper: wrappedValue (aktuellt värde) och projectedValue (själva Binding, tillgängligt via $). När barnvyn ändrar wrappedValue via Binding, överför SwiftUI ändringen till datakällan och ritar om alla beroende vyer. Detta sker synkront inom den aktuella uppdateringscykeln.
Viktig egenskap: @Binding är inte begränsad till en nivås överföring. Binding kan skickas genom flera nivåer av hierarkin — varje barnkomponent får en referens till samma datakälla. En ändring på vilken nivå som helst orsakar en enhetlig uppdatering av alla länkade vyer.
Mekanismen för tvåvägsförbindelse via @Binding bygger på projektion av Property Wrappers. När föräldern deklarerar @State var value: T, genererar SwiftUI automatiskt projektionen $value av typen Binding
struct SliderContainer: View {
@State private var value: Double = 0.5
var body: some View {
VStack {
Text("Värde: \(value)")
SliderView(value: $value)
}
}
}
struct SliderView: View {
@Binding var value: Double
var body: some View {
Slider(value: $value, in: 0...1)
}
}
I exemplet äger SliderContainer @State value, och SliderView får Binding via $value. Reglaget inuti SliderView är kopplat till denna Binding. När reglaget dras ändrar Slider värdet via Binding, vilket automatiskt uppdaterar @State i SliderContainer, och båda vyerna visar det aktuella numret. Hela kedjan fungerar utan en enda callback eller notifiering.
För att skapa Binding från @StateObject eller @ObservedObject används samma projektion: $object.property ger Binding
Före SwiftUI var standardsättet att skicka ändringar uppåt i hierarkin via callbacks och delegater: föräldern skickade en closure, barnkomponenten anropade den vid ändring. @Binding erbjuder ett alternativ med mindre kod och mer deklarativ syntax. Istället för att skicka en slutförandeclosure räcker det att skicka $stateValue.
| Kriterium | @Binding | Callbacks |
|---|---|---|
| Kod | En anteckning + $ | Closure + anrop |
| Flernivå | Automatisk | Kedja av closures |
| Testning | Binding(value:constant) | Mock-closures |
| Läsbarhet | Hög | Medel |
| Flexibilitet | Endast data | Vilken logik som helst |
Använd @Binding när barnvyn bara behöver läsa och ändra värdet. Om sidoeffekter krävs vid ändring (validering, loggning, nätverksförfrågan), kombinera Binding med en callback: skicka Binding för data och closure för händelser. Till exempel kan TextField kopplas till Binding, och onChange startar valideringen.
@Binding tillämpas i flera typiska scenarier. Första — anpassade kontroller: strömbrytare, reglage, färgväljare och andra interaktiva element tar emot Binding för tvåvägssynkronisering. Andra — modala fönster: visningsflaggan för sheet skickas som Binding, vilket gör att barnvyn kan stänga sig själv via presentationMode eller direkt inställning.
Tredje mönstret — formulär med uppdelning. Om ett formulär består av många fält kan varje fält extraheras till en separat komponent som tar emot Binding för sitt värde. Detta förenklar testning och återanvändning av fält mellan olika formulär. Förälderkomponenten förblir den enda ägaren av hela formulärmodellen.
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)
}
}
}
Komponenten FormField tar emot en etikett och en Binding till en sträng. Den visar en rubrik och ett TextField kopplat till den skickade Binding. Vilket formulär som helst kan använda FormField flera gånger genom att skicka $property för varje fält. Detta minskar duplicering av märkspråk och centraliserar stilsättningen av textfält.
SwiftUI tillåter manuell skapande av Binding via initialiseraren Binding(get:set:). Detta är användbart när logik behöver läggas till vid läsning eller skrivning av värdet. Du kan till exempel skapa en Binding som formaterar ett tal före lagring, eller en Binding som synkroniserar värdet med en fjärrserver vid varje ändring.
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)
}
}
I listningen konverterar anpassad emailBinding automatiskt text till gemener och tar bort mellanslag vid varje ändring. TextField använder denna Binding istället för direkt koppling till $email. Ett sådant tillvägagångssätt gör det möjligt att centralisera validering och datatransformation inom Binding, utan att förorena koden med onChange-hanterare.
Det första och vanligaste felet — att skicka värdet istället för Binding. Om en barnkomponent deklarerar @Binding var text: String och föräldern skickar text (utan $), ger kompilatorn ett fel: Cannot convert value of type 'String' to expected argument type 'Binding
Andra felet — Binding på skrivskyddade data. Om barnvyn bara behöver läsa värdet, använd inte @Binding — en vanlig let eller @State från föräldern räcker. Binding innebär skrivmöjlighet och extra ändringsrättigheter försvårar felsökning och bryter mot principen om minimala privilegier.
Tredje problemet — Binding.constant i produktion. Binding.constant(value) skapar en falsk bindning utan återkoppling — ändringar ignoreras. Använd constant endast för prototypframställning och förhandsvisningar (Xcode Previews), men aldrig i verklig kod. För tester, använd Binding(get:set:) med kontrollerat beteende.
Vanliga frågor
@State äger data och hanterar deras lagring på heapen. @Binding refererar bara till befintligt tillstånd utan ägande. @State är alltid private, @Binding — ingångsparameter för barnvyn.
Ja, via initialiseraren Binding(get:set:) eller Binding.constant(value). Binding kan också erhållas från @StateObject via projektionen $object.$property och från Publisher via Binding(get:set:) inuti Subscribe.
@Binding skickas i en kedja: varje mellanliggande komponent deklarerar @Binding och skickar det vidare via $. Alla nivåer refererar till en datakälla i rotvyn.
Binding.constant skapar ett tyst omslag — settern ignorerar nya värden. Det är endast avsett för prototypframställning och SwiftUI Previews, där återkoppling från barnkomponenten inte behövs.
Ja, Binding<T?> stöds. Om du skickar Binding<String?>, kan barnvyn sätta nil. Detta är praktiskt för valfria formulärfält eller tillstånd med återställningsmöjlighet.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också