Einstieg in SwiftUI
Seite 4: @Binding in SwiftUI
Properties auf Basis von @Binding
finden sich übrigens an vielen Stellen im SwiftUI-Framework wieder. Betrachtet sei hier als Beispiel die View Toggle
, die zum Abbilden von Schaltern dient. Jede Toggle
-Instanz benötigt eine @Binding
-Property vom Typ Bool
als Parameter. Diese nutzt Toggle
dazu, einerseits die initiale Darstellung festzulegen (an oder aus) sowie bei einer Änderung die übergebene Datenbasis zu verändern.
Da eine View wie Toggle
an den unterschiedlichsten Stellen zum Einsatz kommt und hierbei immer eine andere Datenbasis nutzt, ist die Verwendung einer @Binding
-Property ideal. So weiß Toggle
lediglich, wo sich die Daten befinden, die für das Erscheinungsbild des Schalters verantwortlich sind, und kann diese bei Betätigen des Schalters direkt anpassen. Der praktische Einsatz von Toggle
ist in einem kleinen Beispiel demonstriert:
struct ContentView: View {
@State var isActive = false
var body: some View {
Toggle(isOn: $isActive) {
Text("Schalter")
}
}
}
Umgang mit externen Daten
Mit Properties, @State
und @Binding
haben Entwickler drei Möglichkeiten kennengelernt, um Informationen abzubilden, die direkter Teil einer View sind. Doch was ist mit jenen Daten, die nicht explizit zu einer View gehören und stattdessen aus einer externen Quelle stammen, beispielsweise dem Model einer App? Für derartige Daten kommt der Property Wrapper @ObservedObject
zum Einsatz. Er wird genauso eingesetzt wie der Property Wrapper @State
, nur dass die zugehörigen Daten hier aus einer externen Quelle stammen und nicht Bestandteil einer View sind.
Bevor man allerdings externe Daten in SwiftUI verwenden kann, sind die noch entsprechend vorzubereiten. Dazu muss man die Daten in Form einer Klasse abbilden, die konform zum ObservableObject
-Protokoll ist. Zusätzlich versieht man jede Property innerhalb der Klasse, bei deren Änderung eine Aktualisierung einer View erfolgen soll, mit dem Property Wrapper @Published
. Damit besitzt das System alle Informationen, die es benötigt, um die externen Daten als Basis für SwiftUI zu nutzen. Ändern sich mit @Published
deklarierte Properties, werden Views, die auf diesen Daten basieren, entsprechend automatisch aktualisiert.
Ein Beispiel für auf die beschriebene Art und Weise angepasste externe Daten stellt die Klasse Settings
im nächsten Codestück dar. Sie ist konform zum ObservableObject
-Protokoll und besitzt die Property username
, die zur Speicherung eines Nutzernamens innerhalb einer App dient. Damit bei einer Änderung des Nutzernamens Views automatisch aktualisiert werden, ist die Property passend mit @Published
deklariert.
class Settings: ObservableObject {
@Published var username = ""
}
Um diese Daten nun als Teil einer SwiftUI-View zu nutzen, erstellt man eine Property des entsprechenden Typs (in diesem Fall Settings
) und deklariert sie mit dem Property Wrapper @ObservedObject
. Im nächsten Beispiel ist das Prinzip zu erkennen. Die dort deklarierte UsernameView
nimmt die Einstellungen über eine settings
-Property entgegen und nutzt die darin enthaltene Information, um den Nutzernamen in einem Label auszugeben. Darüber hinaus verfügt die View über ein Textfeld, über das sich der Nutzername ändern lässt. Dazu wird der TextField
-Instanz der Verweis auf den Nutzernamen als Binding übergeben; das wäre nicht möglich, wenn die settings
-Property nicht mit dem Property Wrapper @ObservedObject
deklariert wäre.
struct UsernameView: View {
@ObservedObject var settings: Settings
var body: some View {
VStack {
Text("Current username: \(settings.username)")
TextField("Username", text: $settings.username)
}
}
}
Eine Alternative zu @ObservedObject
stellt der Property Wrapper @EnvironmentObject
dar. Er hat dieselbe Aufgabe wie @ObservedObject
und erlaubt es, externe Daten in Views zugänglich zu machen. Der Unterschied besteht darin, dass sich diese Daten beim Einsatz von @EnvironmentObject
an einer beliebigen Stelle innerhalb eines Projekts in eine View injizieren lassen. Daten sind so nicht über mehrere View-Ebenen weiterzureichen, bis sie letztlich jene View erreicht haben, für die sie bestimmt sind.
Um Daten einer View auf Basis des Property Wrapper @EnvironmentObject
zu übergeben, kommt die Methode environmentObject(_:)
zum Einsatz, die sich auf allen Views aufrufen lässt. Als Parameter übergibt man eine passende Dateninstanz. Wäre so beispielsweise die settings
-Property der Structure UsernameView
dem vorangegangenen Beispiel mit @EnvironmentObject
deklariert, müsste man eine Instanz der View wie folgt erzeugen:
let mySettings = Settings()
UsernameView().environmentObject(mySettings)
Bei der Arbeit mit @EnvironmentObject
müssen Entwickler aber aufpassen. Der Compiler informiert sie in diesem Fall nicht, falls sie den Aufruf der environmentObject(_:)
-Methode vergessen und so einer View möglicherweise nicht die Daten übergeben, die sie zwingend benötigt. Sollte das tatsächlich der Fall sein, führt das beim Erstellen einer entsprechenden View zu einem Absturz der Anwendung.