在Swift中使用KVO,有如下两种方法:

原OC提供的:

open func addObserver(_ observer: NSObject, forKeyPath keyPath: String, options: NSKeyValueObservingOptions = [], context: UnsafeMutableRawPointer?)

@available(iOS 5.0, *)
open func removeObserver(_ observer: NSObject, forKeyPath keyPath: String, context: UnsafeMutableRawPointer?) open func removeObserver(_ observer: NSObject, forKeyPath keyPath: String)

使用上面提供的方法实现KVO,需要注意一点,keyPath对应的属性,必须要是OC的属性,如果是通过swift定义的属性,必须在属性前添加@objcdynamic修饰才可以,否则KVO将无效果,如下:

class ViewController: UIViewController {

    // swift定义的属性,必须使用@objc和dynamic标注,否则kvo将无效果
@objc dynamic var name: String = "" override func viewDidLoad() {
super.viewDidLoad()
// 添加KVO
addObserver(self, forKeyPath: "name", options: [.new], context: nil) // 修改name值
name = "drbox"
} override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("kvo: name: \(change?[.newKey] as? String ?? "")")
}
}

swift提供的:

func observe<Value>(_ keyPath: KeyPath<ViewController, Value>, options: NSKeyValueObservingOptions = [], changeHandler: @escaping (ViewController, NSKeyValueObservedChange<Value>) -> Void) -> NSKeyValueObservation

使用上面提供的方法实现KVO,注意事项同上,代码如下:

class ViewController: UIViewController {

    // swift定义的属性,必须使用@objc和dynamic标注,否则kvo将无效果
@objc dynamic var name: String = ""
var obs: NSKeyValueObservation? deinit {
// 移除观察者
obs = nil
} override func viewDidLoad() {
super.viewDidLoad() // 添加kvo
obs = observe(\.name, options: [.new], changeHandler: { (_, change) in
print("name: \(change.newValue ?? "")")
}) name = "drbox" } }

使用过rxswift都知道,它同样提供了KVO的实现,实现原理实际上就是对OC的KVO的封装,因此在使用时同样要注意以上事项:@objc dynamic

class ViewController: UIViewController {

    @objc dynamic var name: String = ""
var disposeBag = DisposeBag() override func viewDidLoad() {
super.viewDidLoad() // 方法一:
rx.observe(\.name).bind { str in
print("name1: \(str)")
}.disposed(by: disposeBag)
// 方法二:
rx.observe(String.self, "name").map({ $0 ?? ""}).bind { str in
print("name2: \(str)")
}.disposed(by: disposeBag)
// 方法三:
rx.observeWeakly(String.self, "name").map({ $0 ?? ""}).bind { str in
print("weak name: \(str)")
}.disposed(by: disposeBag) name = "drbox" } }

其中rx.observe与rx.observeWeakly的区别在于前者返回的Observable会对观察者target强持有(strong);后者返回的Observable会对target弱持有(weak)

具体的比较如下:

性能比较:

  • rx.observe 更加高效,因为它是一个 KVO 机制的简单封装。
  • rx.observeWeakly 执行效率要低一些,因为它要处理对象的释放防止弱引用(对象的 dealloc 关系)。

使用场景比较:

  • 在可以使用 rx.observe 的地方都可以使用 rx.observeWeakly。
  • 使用 rx.observe 时路径只能包括 strong 属性,否则就会有系统崩溃的风险。而 rx.observeWeakly 可以用在 weak 属性上。

当然rx.observe也可以决定其返回的Observable是否强持有target,可以设置参数:retainSelf,默认:true(强持有)

// retainSelf
rx.observe(String.self, "name", retainSelf: true).map({ $0 ?? ""}).bind { str in
print("name2: \(str)")
}.disposed(by: disposeBag)

最新文章

  1. Ajax使用WCF实现小票pos机打印源码
  2. C++11中自定义range
  3. 【原】理解javascript中的闭包
  4. mysql使用
  5. ACM:POJ 2739 Sum of Consecutive Prime Numbers-素数打表-尺取法
  6. Django数据库设计中字段为空的方式
  7. 九度oj 1554 区间问题
  8. Hanoi Tower问题分析
  9. Bash Promot
  10. Java中print、printf、println的区别(转载)
  11. javascript DOM对象(2)
  12. AForge.NET是一个专门为开发者和研究者基于C#框架设计的视频录像
  13. hdu 2896 病毒侵袭 AC自动机(查找包含哪些子串)
  14. 数组中的reduce 函数理解
  15. SpringBoot 整合 Redis缓存
  16. C++ gui程序附加dos输出窗口
  17. Hillstone基础上网配置
  18. typename的用法
  19. 模拟器运行报错:ld: symbol(s) not found for architecture x86_64
  20. Java对MongoDB中的数据查询处理

热门文章

  1. StatisticalOutlierRemoval:离群点移除
  2. Vue3 中的组件 provide和inject 传值、获取组件实例的方法getCurrentInstance()
  3. CF750H New Year and Snowy Grid
  4. P4525 【模板】自适应辛普森法 1
  5. 一个基于 gin+ grpc + etcd 等框架开发的小栗子
  6. Python 生成多个空列表 空List 空数组方法
  7. tp-link路由器后台_硬解
  8. 设备树编译链接报错arch/arm/boot/dts/imx50.dtsi:16:42: fatal error: dt-bindings/
  9. DRF排序
  10. linux 替换csv的换行符(Linux 替换^M字符 方法)