Swift'te KVO kullanabilirsiniz, ancak yalnızca alt sınıfın dynamic
özellikleri için kullanabilirsiniz NSObject
. bar
Bir Foo
sınıfın özelliğini gözlemlemek istediğinizi düşünün . Swift 4'te alt sınıfınızda özellik bar
olarak belirtin :dynamic
NSObject
class Foo: NSObject {
@objc dynamic var bar = 0
}
Daha sonra bar
tesisteki değişiklikleri gözlemlemek için kayıt olabilirsiniz . Swift 4 ve Swift 3.2'de, Swift'te Anahtar / Değer Gözlemlemesini Kullanma bölümünde belirtildiği gibi bu büyük ölçüde basitleştirilmiştir :
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)")
}
}
}
Swift 4'te, şimdi ters eğik çizgi karakterini kullanarak güçlü bir tuş yolları yazmamız var ( gözlemlenen nesnenin özelliği \.bar
için anahtar yolu bar
). Ayrıca, tamamlama kapatma modelini kullandığından, gözlemcileri manuel olarak kaldırmamız gerekmez token
(kapsamın dışına çıktığında , gözlemci bizim için kaldırılır) veya super
anahtar, eşleşme. Kapatma sadece bu gözlemci çağrıldığında çağrılır. Daha fazla bilgi için WWDC 2017 videosu, Foundation'daki Yenilikler başlıklı videoya bakın .
Swift 3'te bunu gözlemlemek biraz daha karmaşık, ama Objective-C'de olanlara çok benziyor. Yani, observeValue(forKeyPath keyPath:, of object:, change:, context:)
(a) bağlamımızla uğraştığımızdan emin olursunuz ( super
örneğimizin gözlemlemek için kaydettiği bir şeyi değil ); ve daha sonra (b) gerektiği şekilde ele alın veya super
uygulamaya aktarın. Ve uygun olduğunda kendinizi bir gözlemci olarak çıkardığınızdan emin olun. Örneğin, yeniden konumlandırıldığında gözlemciyi kaldırabilirsiniz:
Swift 3'te:
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])")
}
}
Not: Yalnızca Objective-C içinde temsil edilebilecek özellikleri gözlemleyebilirsiniz. Böylece, jenerikleri, Swift struct
türlerini, Swift enum
türlerini vb. Gözlemleyemezsiniz .
Swift 2 uygulaması hakkında bir tartışma için, aşağıdaki orijinal cevabıma bakın.
Kullanımı dynamic
ile Kvo ulaşmak için anahtar kelime NSObject
alt sınıfları açıklanan Anahtar-Değer Gözlem bölümünde benimsenmesi Kakao Tasarım Kuralları bölüm Kakao ve Objective-C ile kullanma Swift rehberi:
Anahtar / değer gözlemleme, nesnelerin diğer nesnelerin belirtilen özelliklerindeki değişikliklerden haberdar edilmesini sağlayan bir mekanizmadır. Sınıf sınıftan miras aldığı sürece bir Swift sınıfıyla anahtar / değer gözlemini kullanabilirsiniz NSObject
. Swift'te anahtar / değer gözlemini uygulamak için bu üç adımı kullanabilirsiniz.
dynamic
Değiştiriciyi, gözlemlemek istediğiniz herhangi bir özelliğe ekleyin . Hakkında daha fazla bilgi için dynamic
bkz . Dinamik Dağıtım Gereksinimi .
class MyObjectToObserve: NSObject {
dynamic var myDate = NSDate()
func updateDate() {
myDate = NSDate()
}
}
Genel bağlam değişkeni oluşturun.
private var myContext = 0
Anahtar yolu için bir gözlemci ekleyin ve observeValueForKeyPath:ofObject:change:context:
yöntemi geçersiz kılın ve içindeki gözlemciyi kaldırın 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)
}
}
[Not: Bu KVO tartışması daha sonra Swift 3 için uyarlanmış Swift'i Kakao ve Objective-C ile Kullanma kılavuzundan kaldırılmıştır , ancak yine de bu cevabın üst kısmında belirtildiği gibi çalışmaktadır.]
Swift'in kendi yerel mülkiyet gözlemleme sistemine sahip olduğunu belirtmek gerekir , ancak bu, kendi özelliklerinin gözlemlenmesi üzerine gerçekleştirilecek kendi kodunu belirten bir sınıf içindir. Öte yandan KVO, başka bir sınıfın bazı dinamik özelliklerindeki değişiklikleri gözlemlemek için kayıt olmak üzere tasarlanmıştır.