Einstieg in SwiftUI

Seite 4: @Binding in SwiftUI

Inhaltsverzeichnis

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

}

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.