Eine der coolen Funktionen von Swift sind Eigenschaftsbeobachter, vielleicht besser bekannt als willSet und didSet. Jeder, der in Swift programmiert, muss sie verwendet haben. Einige Leute mehr als andere. Und manche verwenden sie vielleicht ein bisschen zu viel, indem sie viele von ihnen zusammen ändern (mich manchmal eingeschlossen). Aber es ist nicht immer ganz offensichtlich, wann sie aufgerufen werden. Vor allem, wenn Sie mit struct zu tun haben, denn structs können etwas seltsam sein. Lassen Sie uns in einige Situationen eintauchen und sehen, was passiert.
Zuweisung
Die offensichtlichste Situation, in der didSet (und willSet) aufgerufen wird, ist die einfache Zuweisung einer Variablen. Stellen Sie sich die folgende Struktur vor:
struct Person {
var name: String
var age: Int
}
Und ein anderer Code, wie z.B. ein View-Controller, der es in einer Variablen mit einem Property Observer verwendet.
class MyViewController: UIViewController {
var person: Person! {
didSet {
print("Person wurde auf '(Person.Name)' mit Alter (Person.Alter) gesetzt")
}
}
override func viewDidLoad() {
Person = Person(Name: "Bob", Alter: 20)
}
}
Wie zu erwarten, wird der Code in didSet ausgeführt, wenn die Ansicht geladen wurde, und das Folgende wird auf der Konsole ausgegeben:
Person wurde mit Alter 20 auf 'Bob' gesetzt
Initialisierung
Auch dies ist ziemlich klar und Sie wissen es wahrscheinlich schon: Eigenschaftsbeobachter werden nicht ausgeführt, wenn die Variable bei der Initialisierung zugewiesen wird.
var person = Person (Name: "Bob", Alter: 20) {
didSet {
print("Person wurde auf '(Person.Name)' mit Alter (Person.Alter) gesetzt")
}
}
Dies führt zu keiner Ausgabe auf der Konsole. Auch wenn Sie Person in der init-Funktion zuweisen würden, wird willSet nicht aufgerufen.
Ändern von Strukturen
Weniger bekannt ist, dass Eigenschaftsbeobachter auch ausgeführt werden, wenn Sie die Memberwerte von Strukturen ändern, ohne die gesamte Struktur (neu) zuzuweisen. Das folgende Beispiel veranschaulicht dies.
class ViewController: UIViewController {
var person = Person (Name: "Bob", Alter: 20) {
didSet {
print("Person wurde auf '(Person.Name)' mit Alter (Person.Alter) gesetzt")
}
}
override func viewDidLoad() {
person.name = "Mike"
person.age = 30
}
}
In diesem Beispiel haben wir die Person in unserer viewDidLoad-Funktion nie neu zugewiesen, aber durch die Änderung des Namens und des Alters wird willSet trotzdem zweimal ausgeführt und wir erhalten als Ausgabe:
Person wurde mit Alter 20 auf 'Mike' eingestellt Person wurde mit 30 Jahren auf 'Mike' eingestellt
Funktionen mutieren
Was für das Ändern von Werten einer struct gilt, gilt auch für mutierende struct-Funktionen. Der Aufruf einer solchen Funktion führt
struct Person {
var name: String
var age: Int
mutating func incrementAge() {
wenn Alter < 100 {
Alter++
}
}
}
Hier haben wir eine Mutationsfunktion hinzugefügt, die das Alter erhöht, solange das Alter unter 100 liegt.
class ViewController: UIViewController {
var person = Person (Name: "Bob", Alter: 98) {
didSet {
print("Person wurde auf '(Person.Name)' mit Alter (Person.Alter) gesetzt")
}
}
override func viewDidLoad() {
person.incrementAge()
person.incrementAge()
person.incrementAge()
person.incrementAge()
}
}
Unser willSet wird 4 Mal aufgerufen, obwohl sich bei den letzten beiden Malen nichts geändert hat.
Person wurde mit 99 Jahren auf 'Bob' eingestellt Person wurde mit Alter 100 auf 'Bob' gesetzt Person wurde mit Alter 100 auf 'Bob' gesetzt Person wurde mit Alter 100 auf 'Bob' gesetzt
Änderungen innerhalb von Eigenschaftsbeobachtern
Es ist auch möglich, Änderungen an der Variablen innerhalb ihrer eigenen Eigenschaftsbeobachter vorzunehmen. Sie können die gesamte Variable neu zuweisen, ihre Werte ändern oder Mutationsfunktionen für sie aufrufen. Wenn Sie dies innerhalb eines Eigenschaftsbeobachters tun, werden die Eigenschaftsbeobachter nicht ausgelöst, da dies höchstwahrscheinlich zu einer Endlosschleife führen würde. Denken Sie daran, dass eine Änderung in willSet wirkungslos bleibt, da Ihre Änderung durch den Wert überschrieben wird, der ursprünglich gesetzt wurde (dies führt auch zu einer netten Warnung in Xcode).
class ViewController: UIViewController {
var person = Person (Name: "Bob", Alter: 98) {
didSet {
print("Person wurde auf '(Person.Name)' mit Alter (Person.Alter) gesetzt")
if person.name != oldValue.name {
person.age = 0
print("Das Alter der Person '(Person.Name)' wurde auf 0 gesetzt")
}
}
}
override func viewDidLoad() {
person.name = "Mike"
}
}
Warum es wichtig ist
Warum ist das alles so wichtig, werden Sie vielleicht denken. Nun, Sie müssen vielleicht überdenken, welche Art von Logik Sie in Ihre Eigenschaftsbeobachter einbauen und welche Sie außerhalb platzieren. Und all dies gilt auch für Arrays und Dictionaries, denn auch sie sind Strukturen. Nehmen wir an, Sie haben ein Array mit Zahlen, die sich ändern können, und jedes Mal, wenn sie sich ändern, möchten Sie Ihre Benutzeroberfläche aktualisieren. Aber Sie möchten die Zahlen auch sortieren. Der folgende Code sieht auf den ersten Blick vielleicht ganz gut aus:
class ViewController: UIViewController {
var Zahlen: [Int] = [] {
didSet {
updateUI()
}
}
override func viewDidLoad() {
refreshNumbers()
}
func refreshNumbers() {
Zahlen = [random() % 10, random() % 10, random() % 10, random() % 10]
zahlen.sortInPlace()
}
func updateUI() {
print("UI: (Zahlen)")
}
}
Jedes Mal, wenn sich die Zahlen ändern, wird die Benutzeroberfläche aktualisiert. Da sortInPlace aber auch den Property Observer auslöst, wird die Benutzeroberfläche zweimal aktualisiert:
UI: [3, 6, 7, 5] UI: [3, 5, 6, 7]
Wir sollten also sortInPlace in willSet einfügen, bevor wir updateUI aufrufen.
Verfasst von

Lammert Westerhoff
Contact



