Swift hat eine Eigenschaftsdeklarationssyntax, die der von C # sehr ähnlich ist:
var foo: Int {
get { return getFoo() }
set { setFoo(newValue) }
}
Es hat aber auch willSet
und didSet
Aktionen. Diese werden vor bzw. nach dem Aufruf des Setters aufgerufen. Was ist ihr Zweck, wenn man bedenkt, dass Sie nur den gleichen Code im Setter haben könnten?
get
&set
) besteht im Wesentlichen darin, eine Eigenschaft basierend auf einer anderen Eigenschaft berechnen zu lassen, z. B. die Umwandlung eines Etikettstext
in ein JahrInt
.didSet
&willSet
gibt es zu sagen ... hey, dieser Wert wurde gesetzt, jetzt machen wir das, zB Unsere dataSource wurde aktualisiert ... also lasst uns die tableView neu laden, damit sie neue Zeilen enthält. Ein weiteres Beispiel finden Sie in der Antwort von dfri, wie Sie Delegierte anrufen könnendidSet
Antworten:
Der Punkt scheint zu sein, dass Sie manchmal eine Eigenschaft benötigen, die über automatischen Speicher und ein gewisses Verhalten verfügt, um beispielsweise andere Objekte darüber zu informieren, dass sich die Eigenschaft gerade geändert hat. Wenn Sie nur
get
/ habenset
, benötigen Sie ein anderes Feld, um den Wert zu speichern. MitwillSet
unddidSet
können Sie Maßnahmen ergreifen, wenn der Wert geändert wird, ohne dass ein weiteres Feld erforderlich ist. Zum Beispiel in diesem Beispiel:myProperty
Gibt bei jeder Änderung den alten und den neuen Wert aus. Mit nur Getter und Setter würde ich dies stattdessen brauchen:So
willSet
unddidSet
stellt eine Wirtschaft von ein paar Zeilen, und weniger Lärm in der Feldliste.quelle
willSet
unddidSet
werden nicht aufgerufen, wenn Sie die Eigenschaft innerhalb einer Init-Methode festlegen, wie Apple feststellt:willSet and didSet observers are not called when a property is first initialized. They are only called when the property’s value is set outside of an initialization context.
myArrayProperty.removeAtIndex(myIndex)
... Nicht erwartet.Ich verstehe, dass set und get für berechnete Eigenschaften gelten (keine Sicherung von gespeicherten Eigenschaften ).
Wenn Sie von einem Objective-C kommen, denken Sie daran, dass sich die Namenskonventionen geändert haben. In Swift wird eine iVar- oder Instanzvariable als gespeicherte Eigenschaft bezeichnet
Beispiel 1 (schreibgeschützte Eigenschaft) - mit Warnung:
Dies führt zu einer Warnung, da dies zu einem rekursiven Funktionsaufruf führt (der Getter ruft sich selbst auf). Die Warnung in diesem Fall lautet "Versuch, 'Test' in seinem eigenen Getter zu ändern".
Beispiel 2. Bedingtes Lesen / Schreiben - mit Warnung
Ähnliches Problem - Sie können dies nicht tun, da der Setter rekursiv aufgerufen wird. Beachten Sie außerdem, dass sich dieser Code nicht über keine Initialisierer beschwert, da keine zu initialisierende Eigenschaft gespeichert ist .
Beispiel 3. Berechnete Lese- / Schreibeigenschaft - mit Hintergrundspeicher
Hier ist ein Muster, das die bedingte Einstellung einer tatsächlich gespeicherten Eigenschaft ermöglicht
Hinweis Die tatsächlichen Daten heißen _test (obwohl es sich um beliebige Daten oder Datenkombinationen handeln kann). Beachten Sie auch die Notwendigkeit, einen Anfangswert anzugeben (alternativ müssen Sie eine init-Methode verwenden), da _test tatsächlich eine Instanzvariable ist
Beispiel 4. Verwenden von will und did set
Hier sehen wir, wie willSet und didSet eine Änderung in einer tatsächlich gespeicherten Eigenschaft abfangen. Dies ist nützlich zum Senden von Benachrichtigungen, Synchronisieren usw. (siehe Beispiel unten).
Beispiel 5. Konkretes Beispiel - ViewController Container
Beachten Sie die Verwendung von BEIDEN berechneten und gespeicherten Eigenschaften. Ich habe eine berechnete Eigenschaft verwendet, um zu verhindern, dass derselbe Wert zweimal festgelegt wird (um zu verhindern, dass schlimme Dinge passieren!). Ich habe willSet und didSet verwendet, um Benachrichtigungen an viewController weiterzuleiten (siehe UIViewController-Dokumentation und Informationen zu viewController-Containern).
Ich hoffe das hilft und bitte jemanden schreien, wenn ich hier irgendwo einen Fehler gemacht habe!
quelle
//I can't see a way to 'stop' the value being set to the same controller - hence the computed property
Warnung verschwinden, nachdem ichif let newViewController = _childVC {
anstelle vonif (_childVC) {
get
, denke ich, müssen Sie hinzufügenif _childVC == nil { _childVC = something }
und dannreturn _childVC
.Diese werden als Immobilienbeobachter bezeichnet :
Auszug aus: Apple Inc. "Die schnelle Programmiersprache". iBooks. https://itun.es/ca/jEUH0.l
Ich vermute, es soll Dinge berücksichtigen, die wir traditionell mit KVO tun würden, wie Datenbindung mit UI-Elementen oder Auslösen von Nebenwirkungen beim Ändern einer Eigenschaft, Auslösen eines Synchronisierungsprozesses, Hintergrundverarbeitung usw. usw.
quelle
quelle
Sie können
didSet
die Variable auch verwenden , um die Variable auf einen anderen Wert zu setzen. Dies führt nicht dazu, dass der Beobachter erneut angerufen wird, wie im Eigenschaftenhandbuch angegeben . Dies ist beispielsweise hilfreich, wenn Sie den Wert wie folgt begrenzen möchten:quelle
Die vielen gut geschriebenen Antworten decken die Frage gut ab, aber ich werde im Detail eine Ergänzung erwähnen, die meiner Meinung nach eine Behandlung wert ist.
Die
willSet
unddidSet
-Eigenschaftsbeobachter können zum Aufrufen von Delegaten verwendet werden, z. B. für Klasseneigenschaften, die immer nur durch Benutzerinteraktion aktualisiert werden, bei denen Sie jedoch vermeiden möchten, dass der Delegat bei der Objektinitialisierung aufgerufen wird.Ich zitiere Klaas hochgestimmten Kommentar zur akzeptierten Antwort:
Dies ist recht ordentlich, da es bedeutet, dass die
didSet
Eigenschaft beispielsweise eine gute Wahl für den Startpunkt für delegierte Rückrufe und Funktionen für Ihre eigenen benutzerdefinierten Klassen ist.Betrachten Sie als Beispiel ein benutzerdefiniertes Benutzersteuerungsobjekt mit einer Schlüsseleigenschaft
value
(z. B. Position in der Bewertungssteuerung), die als Unterklasse vonUIView
:Danach können Ihre Delegatenfunktionen beispielsweise in einigen View-Controllern verwendet werden, um wichtige Änderungen im Modell zu beobachten
CustomViewController
, ähnlich wie Sie die inhärenten Delegatenfunktionen derUITextFieldDelegate
for-UITextField
Objekte (ztextFieldDidEndEditing(...)
. B. ) verwenden würden.Verwenden Sie für dieses einfache Beispiel einen Delegatenrückruf von der
didSet
Eigenschaft classvalue
, um einem Ansichtscontroller mitzuteilen, dass einem seiner Outlets eine Modellaktualisierung zugeordnet ist:Hier wurde die
value
Eigenschaft gekapselt, aber im Allgemeinen: Achten Sie in solchen Situationen darauf, dievalue
Eigenschaft descustomUserControl
Objekts nicht im Bereich der zugehörigen Delegatenfunktion (hier :)didChangeValue()
im Ansichts-Controller zu aktualisieren, da dies sonst der Fall ist unendliche Rekursion.quelle
Beachten Sie, dass
willSet
ein ParameternamedidSet
erforderlich ist , um dies zu umgehen.quelle
Getter und Setter sind manchmal zu schwer zu implementieren, um die richtigen Wertänderungen zu beobachten. Normalerweise erfordert dies eine zusätzliche vorübergehende Variablenbehandlung und zusätzliche Überprüfungen, und Sie sollten selbst diese winzige Arbeit vermeiden, wenn Sie Hunderte von Gettern und Setzern schreiben. Diese Sachen sind für die Situation.
quelle
willSet
didSet
In Ihrer eigenen (Basis-) Klasse
willSet
unddidSet
sind ziemlich redundant , da Sie stattdessen eine berechnete Eigenschaft definieren können (dh get- und set-Methoden), die auf a zugreift und_propertyVariable
die gewünschte Vor- und Nachbearbeitung ausführt .Wenn jedoch , Sie eine Klasse außer Kraft setzen , wenn die Eigenschaft bereits definiert , dann das
willSet
unddidSet
sind nützlich und nicht überflüssig!quelle
Eine Sache, die
didSet
wirklich praktisch ist, ist, wenn Sie Steckdosen verwenden, um zusätzliche Konfiguration hinzuzufügen.quelle
Ich kenne C # nicht, aber mit ein wenig Rätselraten denke ich, ich verstehe was
tut. Es sieht dem, was Sie in Swift haben, sehr ähnlich, aber es ist nicht dasselbe: In Swift haben Sie das
getFoo
und nichtsetFoo
. Das ist kein kleiner Unterschied: Es bedeutet, dass Sie keinen zugrunde liegenden Speicher für Ihren Wert haben.Swift hat Eigenschaften gespeichert und berechnet.
Eine berechnete Eigenschaft hat
get
und kann habenset
(wenn es beschreibbar ist). Der Code im Getter und Setter muss dies jedoch in anderen Eigenschaften tun, wenn sie tatsächlich einige Daten speichern müssen . Es gibt keinen Hintergrundspeicher.Eine gespeicherte Eigenschaft verfügt dagegen über einen Sicherungsspeicher. Aber es funktioniert nicht hat
get
undset
. Stattdessen hat eswillSet
unddidSet
was Sie verwenden können, um variable Änderungen zu beobachten und schließlich Nebenwirkungen auszulösen und / oder den gespeicherten Wert zu ändern. Sie habenwillSet
unddidSet
für berechnete Eigenschaften nicht und Sie benötigen sie nicht, da Sie für berechnete Eigenschaften den Code verwenden könnenset
, um Änderungen zu steuern.quelle
getFoo
undsetFoo
sind einfache Platzhalter für alles, was die Getter und Setter tun sollen. C # braucht sie auch nicht. (Ich habe ein paar syntaktische Feinheiten verpasst, als ich gefragt habe, bevor ich Zugriff auf den Compiler hatte.)