Sie können KVO in Swift verwenden, jedoch nur für dynamicEigenschaften der NSObjectUnterklasse. Bedenken Sie, dass Sie die barEigenschaft einer FooKlasse beobachten möchten. Geben Sie in Swift 4 barals dynamicEigenschaft in Ihrer NSObjectUnterklasse Folgendes an:
class Foo: NSObject {
@objc dynamic var bar = 0
}
Sie können sich dann registrieren, um Änderungen an der barEigenschaft 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 \.barist der Schlüsselpfad für die barEigenschaft des beobachteten Objekts). Da das Abschlussmuster für die Fertigstellung verwendet wird, müssen wir Beobachter nicht manuell entfernen (wenn der tokenGültigkeitsbereich ausfällt, wird der Beobachter für uns entfernt), und wir müssen uns auch nicht darum kümmern, die superImplementierung 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 superInstanz zur Beobachtung registriert hat); und dann (b) entweder damit umgehen oder es nach superBedarf 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- structTypen, Swift- enumTypen usw. beobachten.
Eine Diskussion der Swift 2-Implementierung finden Sie in meiner ursprünglichen Antwort unten.
Unter Verwendung des dynamicKeyword - KVO zu erreichen mit NSObjectSubklassen 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 NSObjectKlasse erbt . Mit diesen drei Schritten können Sie die Schlüsselwertbeobachtung in Swift implementieren.
Fügen Sie den dynamicModifikator zu jeder Eigenschaft hinzu, die Sie beobachten möchten. Weitere Informationen dazu dynamicfinden 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.