Puoi usare KVO in Swift, ma solo per le dynamicproprietà della NSObjectsottoclasse. Considera che volevi osservare la barproprietà di una Fooclasse. In Swift 4, specifica barcome dynamicproprietà nella NSObjectsottoclasse:
class Foo: NSObject {
@objc dynamic var bar = 0
}
È quindi possibile registrarsi per osservare le modifiche alla barproprietà. In Swift 4 e Swift 3.2, questo è stato notevolmente semplificato, come indicato in Uso dell'osservazione dei valori-chiave in Swift :
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)")
}
}
}
Nota, in Swift 4, ora abbiamo una forte tipizzazione di keypath usando il carattere barra rovesciata ( \.barè il keypath per la barproprietà dell'oggetto che si sta osservando). Inoltre, poiché utilizza il modello di chiusura del completamento, non è necessario rimuovere manualmente gli osservatori (quando il tokencampo di applicazione non rientra, l'osservatore viene rimosso per noi) né dobbiamo preoccuparci di chiamare l' superimplementazione se la chiave non lo fa incontro. La chiusura viene chiamata solo quando viene invocato questo particolare osservatore. Per ulteriori informazioni, vedere il video del WWDC 2017, Novità nella Fondazione .
In Swift 3, osservare questo, è un po 'più complicato, ma molto simile a quello che si fa in Objective-C. Vale a dire, implementeresti observeValue(forKeyPath keyPath:, of object:, change:, context:)quale (a) assicurati che abbiamo a che fare con il nostro contesto (e non qualcosa che la nostra superistanza si era registrata per osservare); e poi (b) gestirlo o passarlo superall'implementazione, se necessario. E assicurati di rimuoverti come osservatore quando appropriato. Ad esempio, è possibile rimuovere l'osservatore quando viene deallocato:
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])")
}
}
Nota, puoi solo osservare le proprietà che possono essere rappresentate in Objective-C. Pertanto, non è possibile osservare generici, structtipi Swift enum, tipi Swift , ecc.
Per una discussione sull'implementazione di Swift 2, vedi la mia risposta originale, di seguito.
L'uso della dynamicparola chiave per ottenere KVO con le NSObjectsottoclassi è descritto nella sezione Osservazione dei valori-chiave del capitolo Adozione di convenzioni di progettazione del cacao della guida Uso di Swift con cacao e Objective-C :
L'osservazione del valore-chiave è un meccanismo che consente agli oggetti di ricevere notifiche delle modifiche alle proprietà specificate di altri oggetti. Puoi utilizzare l'osservazione del valore-chiave con una classe Swift, purché la classe erediti dalla NSObjectclasse. Puoi utilizzare questi tre passaggi per implementare l'osservazione del valore-chiave in Swift.
Aggiungi il dynamicmodificatore a qualsiasi proprietà che desideri osservare. Per ulteriori informazioni su dynamic, vedere Richiesta di invio dinamico .
class MyObjectToObserve: NSObject {
dynamic var myDate = NSDate()
func updateDate() {
myDate = NSDate()
}
}
Crea una variabile di contesto globale.
private var myContext = 0
Aggiungi un osservatore per il percorso chiave, sovrascrivi il observeValueForKeyPath:ofObject:change:context:metodo e rimuovi l'osservatore 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)
}
}
[Nota, questa discussione KVO è stata successivamente rimossa dalla guida Uso di Swift con Cocoa e Objective-C , che è stata adattata per Swift 3, ma funziona ancora come indicato all'inizio di questa risposta.]
Vale la pena notare che Swift ha il proprio sistema di osservazione delle proprietà native , ma questo è per una classe che specifica il proprio codice che verrà eseguito all'osservazione delle proprie proprietà. KVO, d'altra parte, è progettato per registrarsi per osservare le modifiche ad alcune proprietà dinamiche di altre classi.