1、属性观察器 Swift 提供了属性观察器
来监听自身存储属性
的变化。观察器只能用于监听非lazy
存储属性。对于计算属性,它已经内含了get{}
和set{}
,闭包内已经知道属性的变化,不需要再提供观察器。对于从父类继承下来的存储属性或计算属性,我们可以在子类中重写属性的getter
和setter
来为它们添加属性观察器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Student { var nick : String { willSet { print ("++++New value:\(newValue) " ) } didSet { print ("++++Old value:\(oldValue) " ) } } init (name :String ) { self .nick = name } }
调用及输出结果:
1 2 3 4 5 var st = Student(name: "HALO" )st .nick = "james" ++++New value:james ++++Old value:HALO
观察器只能用来观察自身属性(包括从父类继承下来的属性)的变化。
2、使用KVO观察属性 条件1:观察者和被观察者都要继承自NSObject
KVO 是 OC 中的特性,在 OC 中它是基于 runtime 的动态分发机制和 KVC,通过key
来监听value
的变化。OC 中所有的类都直接或间接继承自 NSObject,而根类 NSObject 默认遵守了NSKeyValueCoding
协议,所以这些类才能实现 KVO。Swift class 只有继承了 NSObject 才能拥有这些特性。对于没有父类或者不继承 NSObject 的情况,则可以使用上面提到的观察器来实现此功能。
条件2:需要将属性标记为@objc
和dynamic
@objc
标记用来将 Swift 类中的属性暴露给 OC;你也可以将类标注为@objcMembers
,使用这种标注的类会隐式地为类中所有的属性和方法添加@objc
标注。
另外,Swift 中默认关闭了动态派发机制,声明为@objc
的属性或方法有可能会被 Swift 优化为静态调用,不一定会动态派发,所以还需将属性标记为dynamic
才能开启运行时从而监听属性的变化。
方案1(addObserver:) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class People : NSObject { @objc dynamic var name = "defaultName" func updateName (pName :String ) -> () { name = pName } override init () { super .init () addObserver(self , forKeyPath: "name" , options: [.new,.old], context: nil ) } override func observeValue (forKeyPath keyPath : String ?, of object : Any ? , change : [NSKeyValueChangeKey : Any ]? , context : UnsafeMutableRawPointer ?) { if keyPath == "name" , let newName = change? [.newKey] { print ("++++name updated to: \(newName) " ) }else { super .observeValue(forKeyPath: keyPath, of: object, change: change, context: context) } } deinit { removeObserver(self , forKeyPath: "name" , context: nil ) print ("++++已移除监听" ) } }
调用方法与输出结果:
1 2 3 4 5 6 7 8 let people = People() people.updateName(pName : "Dav" ) people.setValue("Hello" , forKey : "name" ) ++++name updated to : Dav ++++name updated to : Hello ++++已移除监听
方案2(observe闭包) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class People : NSObject { @objc dynamic var name = "defaultName" func updateName (pName :String ) -> () { name = pName } }class Observer : NSObject { @objc var objToObserve : People var observation : NSKeyValueObservation ? init (object : People ) { objToObserve = object super .init () observation = observe(\.objToObserve.name,options: [.old, .new], changeHandler: { (object, change) in print ("name updated from: \(change.oldValue! ) , updated to: \(change.newValue! ) " ) }) } deinit { print ("++++Observer Deinited" ) } }
调用方法与输出结果如下:
1 2 3 4 5 6 7 8 9 let people = People() let observer = Observer(object : people ) people.updateName(pName : "Dav" ) people.setValue("Hello" , forKey : "name" ) ++++name updated from: defaultName, updated to : Dav ++++name updated from: Dav, updated to : Hello ++++Observer Deinited
相关参考
#©swift官方文档
#©自己实现KVO