Sie können KVO in Swift verwenden, jedoch nur für dynamic
Eigenschaften der NSObject
Unterklasse. Bedenken Sie, dass Sie die bar
Eigenschaft einer Foo
Klasse beobachten möchten. Geben Sie in Swift 4 bar
als dynamic
Eigenschaft in Ihrer NSObject
Unterklasse Folgendes an:
class Foo: NSObject {
@objc dynamic var bar = 0
}
Sie können sich dann registrieren, um Änderungen an der bar
Eigenschaft zu beobachten . In Swift 4 und Swift 3.2 wurde dies erheblich vereinfacht, wie unter Verwenden der Schlüsselwertbeobachtung in Swift beschrieben :
class MyObject {
private var token: NSKeyValueObservation
var objectToObserve = Foo()
init() {
token = objectToObserve.observe(\.bar) { [weak self] object, change in // the `[weak self]` is to avoid strong reference cycle; obviously, if you don't reference `self` in the closure, then `[weak self]` is not needed
print("bar property is now \(object.bar)")
}
}
}
Beachten Sie, dass in Swift 4 jetzt Schlüsselpfade mit dem Backslash-Zeichen stark eingegeben werden (dies \.bar
ist der Schlüsselpfad für die bar
Eigenschaft des beobachteten Objekts). Da das Abschlussmuster für die Fertigstellung verwendet wird, müssen wir Beobachter nicht manuell entfernen (wenn der token
Gültigkeitsbereich ausfällt, wird der Beobachter für uns entfernt), und wir müssen uns auch nicht darum kümmern, die super
Implementierung aufzurufen , wenn der Schlüssel dies nicht tut Spiel. Die Schließung wird nur aufgerufen, wenn dieser bestimmte Beobachter aufgerufen wird. Weitere Informationen finden Sie im WWDC 2017-Video " Was ist neu in Foundation?" .
Um dies zu beobachten, ist es in Swift 3 etwas komplizierter, aber sehr ähnlich zu dem, was man in Objective-C macht. Sie würden nämlich implementieren, observeValue(forKeyPath keyPath:, of object:, change:, context:)
was (a) sicherstellt, dass wir uns mit unserem Kontext befassen (und nicht mit etwas, das unsere super
Instanz zur Beobachtung registriert hat); und dann (b) entweder damit umgehen oder es nach super
Bedarf an die Implementierung weitergeben. Und stellen Sie sicher, dass Sie sich gegebenenfalls als Beobachter entfernen. Beispielsweise können Sie den Beobachter entfernen, wenn er freigegeben wird:
In Swift 3:
class MyObject: NSObject {
private var observerContext = 0
var objectToObserve = Foo()
override init() {
super.init()
objectToObserve.addObserver(self, forKeyPath: #keyPath(Foo.bar), options: [.new, .old], context: &observerContext)
}
deinit {
objectToObserve.removeObserver(self, forKeyPath: #keyPath(Foo.bar), context: &observerContext)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard context == &observerContext else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
// do something upon notification of the observed object
print("\(keyPath): \(change?[.newKey])")
}
}
Beachten Sie, dass Sie nur Eigenschaften beobachten können, die in Objective-C dargestellt werden können. Daher können Sie keine Generika, Swift- struct
Typen, Swift- enum
Typen usw. beobachten.
Eine Diskussion der Swift 2-Implementierung finden Sie in meiner ursprünglichen Antwort unten.
Unter Verwendung des dynamic
Keyword - KVO zu erreichen mit NSObject
Subklassen in dem beschriebenen Schlüsselwert Observing Abschnitt der Annahme Cocoa Designs Konventionen Kapitel der Verwendung von Swift mit Cocoa und Objective-C Anleitung:
Das Beobachten von Schlüsselwerten ist ein Mechanismus, mit dem Objekte über Änderungen an bestimmten Eigenschaften anderer Objekte benachrichtigt werden können. Sie können die Schlüsselwertbeobachtung mit einer Swift-Klasse verwenden, solange die Klasse von der NSObject
Klasse erbt . Mit diesen drei Schritten können Sie die Schlüsselwertbeobachtung in Swift implementieren.
Fügen Sie den dynamic
Modifikator zu jeder Eigenschaft hinzu, die Sie beobachten möchten. Weitere Informationen dazu dynamic
finden Sie unter Erfordernis eines dynamischen Versands .
class MyObjectToObserve: NSObject {
dynamic var myDate = NSDate()
func updateDate() {
myDate = NSDate()
}
}
Erstellen Sie eine globale Kontextvariable.
private var myContext = 0
Fügen Sie einen Beobachter für den Schlüsselpfad hinzu, überschreiben Sie die observeValueForKeyPath:ofObject:change:context:
Methode und entfernen Sie den Beobachter in deinit
.
class MyObserver: NSObject {
var objectToObserve = MyObjectToObserve()
override init() {
super.init()
objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New, context: &myContext)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if context == &myContext {
if let newValue = change?[NSKeyValueChangeNewKey] {
print("Date changed: \(newValue)")
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
deinit {
objectToObserve.removeObserver(self, forKeyPath: "myDate", context: &myContext)
}
}
[Beachten Sie, dass diese KVO-Diskussion später aus dem Handbuch „ Swift mit Kakao und Objective-C verwenden“ entfernt wurde, das für Swift 3 angepasst wurde, aber weiterhin wie oben in dieser Antwort beschrieben funktioniert.]
Es ist erwähnenswert, dass Swift über ein eigenes natives Eigenschaftsbeobachtungssystem verfügt, dies gilt jedoch für eine Klasse, die ihren eigenen Code angibt, der bei Beobachtung ihrer eigenen Eigenschaften ausgeführt wird. KVO hingegen ist so konzipiert, dass es sich registriert, um Änderungen an einer dynamischen Eigenschaft einer anderen Klasse zu beobachten.