Anda dapat menggunakan KVO di Swift, tetapi hanya untuk dynamic
properti NSObject
subclass. Pertimbangkan bahwa Anda ingin mengamati bar
properti Foo
kelas. Di Swift 4, tentukan bar
sebagai dynamic
properti di NSObject
subkelas Anda :
class Foo: NSObject {
@objc dynamic var bar = 0
}
Anda kemudian dapat mendaftar untuk mengamati perubahan pada bar
properti. Dalam Swift 4 dan Swift 3.2, ini telah sangat disederhanakan, seperti diuraikan dalam Menggunakan Pengamatan Nilai-Kunci di 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)")
}
}
}
Catatan, dalam Swift 4, kita sekarang memiliki pengetikan keypath yang kuat menggunakan karakter backslash ( \.bar
adalah keypath untuk bar
properti objek yang diamati). Juga, karena menggunakan pola penutupan penyelesaian, kita tidak harus menghapus pengamat secara manual (ketika token
jatuh di luar ruang lingkup, pengamat dihapus untuk kita) juga tidak perlu khawatir tentang memanggil super
implementasi jika kuncinya tidak pertandingan. Penutupan ini dipanggil hanya ketika pengamat khusus ini dipanggil. Untuk informasi lebih lanjut, lihat video WWDC 2017, What's New in Foundation .
Dalam Swift 3, untuk mengamati ini, ini sedikit lebih rumit, tetapi sangat mirip dengan apa yang dilakukan di Objective-C. Yaitu, Anda akan mengimplementasikan observeValue(forKeyPath keyPath:, of object:, change:, context:)
yang mana (a) memastikan kita berurusan dengan konteks kita (dan bukan sesuatu yang super
terdaftar untuk diamati oleh contoh kita ); dan kemudian (b) menanganinya atau meneruskannya ke super
implementasi, sebagaimana diperlukan. Dan pastikan untuk melepaskan diri Anda sebagai pengamat saat yang tepat. Misalnya, Anda dapat menghapus pengamat saat itu tidak dialokasikan:
Dalam 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])")
}
}
Catatan, Anda hanya bisa mengamati properti yang bisa direpresentasikan dalam Objective-C. Dengan demikian, Anda tidak dapat mengamati obat generik, struct
tipe Swift enum
, tipe Swift , dll.
Untuk diskusi tentang implementasi Swift 2, lihat jawaban asli saya, di bawah ini.
Menggunakan dynamic
kata kunci untuk mencapai KVO dengan NSObject
subkelas dijelaskan di bagian Pengamatan Nilai-Kunci pada bab Mengadopsi Konvensi Desain Kakao dari Menggunakan Swift dengan Kakao dan panduan Objective-C :
Pengamatan nilai-kunci adalah mekanisme yang memungkinkan objek untuk diberitahu tentang perubahan pada properti tertentu dari objek lain. Anda bisa menggunakan mengamati nilai kunci dengan kelas Swift, selama kelas tersebut mewarisi dari NSObject
kelas. Anda dapat menggunakan tiga langkah ini untuk menerapkan mengamati kunci-nilai di Swift.
Tambahkan dynamic
pengubah ke properti apa pun yang ingin Anda amati. Untuk informasi lebih lanjut tentang dynamic
, lihat Membutuhkan Pengiriman Dinamis .
class MyObjectToObserve: NSObject {
dynamic var myDate = NSDate()
func updateDate() {
myDate = NSDate()
}
}
Buat variabel konteks global.
private var myContext = 0
Tambahkan pengamat untuk jalur-kunci, dan timpa observeValueForKeyPath:ofObject:change:context:
metode, dan hapus pengamat di 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)
}
}
[Catatan, diskusi KVO ini kemudian telah dihapus dari panduan Menggunakan Swift dengan Kakao dan Objective-C , yang telah diadaptasi untuk Swift 3, tetapi masih berfungsi seperti yang dijabarkan di bagian atas jawaban ini.]
Perlu dicatat bahwa Swift memiliki sistem pengamat properti asli sendiri , tetapi itu untuk kelas yang menetapkan kode sendiri yang akan dilakukan setelah mengamati propertinya sendiri. KVO, di sisi lain, dirancang untuk mendaftar untuk mengamati perubahan pada beberapa properti dinamis dari beberapa kelas lain.