在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)

Swift中使用KVO的更多相关文章

  1. how to use kvo with swift (怎样在swift中使用kvo)

  2. 一览Swift中的常用关键字

    要学习Swift这门语言,就必须先了解Swift的关键字及对应的解释.这里就列一下在Swift中常用到的关键字. 关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符 ...

  3. Swift 中枚举

    Swift 中枚举高级用法及实践 字数11017 阅读479 评论0 喜欢20 title: "Swift 中枚举高级用法及实践"date: 2015-11-20tags: [AP ...

  4. Combine 框架,从0到1 —— 4.在 Combine 中使用 KVO

      本文首发于 Ficow Shen's Blog,原文地址: Combine 框架,从0到1 -- 4.在 Combine 中使用 KVO.   内容概览 前言 用 KVO 监控改动 将 KVO 代 ...

  5. swift 中关于open ,public ,fileprivate,private ,internal,修饰的说明

    关于 swift 中的open ,public ,fileprivate,private, internal的区别 以下按照修饰关键字的访问约束范围 从约束的限定范围大到小的排序进行说明 open,p ...

  6. 阿里巴巴最新开源项目 - [HandyJSON] 在Swift中优雅地处理JSON

    项目名称:HandyJSON 项目地址:https://github.com/alibaba/handyjson 背景 JSON是移动端开发常用的应用层数据交换协议.最常见的场景便是,客户端向服务端发 ...

  7. Swift中的可选链与内存管理(干货系列)

    干货之前:补充一下可选链(optional chain) class A { var p: B? } class B { var p: C? } class C { func cm() -> S ...

  8. 在Swift中实现单例方法

    在写Swift的单例方法之前可以温习一下Objective-C中单例的写法: + (instancetype)sharedSingleton{ static id instance; static d ...

  9. [翻译]理解Swift中的Optional

    原文出处:Understanding Optionals in Swift 苹果新的Swift编程语言带来了一些新的技巧,能使软件开发比以往更方便.更安全.然而,一个很有力的特性Optional,在你 ...

  10. 窥探Swift之使用Web浏览器编译Swift代码以及Swift中的泛型

    有的小伙伴会问:博主,没有Mac怎么学Swift语言呢,我想学Swift,但前提得买个Mac.非也,非也.如果你想了解或者初步学习Swift语言的话,你可以登录这个网站:http://swiftstu ...

随机推荐

  1. Visual Studio更改项目文件夹名称

    一.VS打开项目解决方案(按以下顺序操作) PS:如果已经出错,打不开.sln文件,就从第三步开始操作,进入目录更改对应其.csproj文件名称即可 1.选择要更改的项目或类库,右键属性,更改程序集名 ...

  2. servlet传入多个数据

    通过&来传入值:<a href="bookquery?page=1&nameBook=&author=&publisher=>1</a> ...

  3. 关于vue项目和内嵌iframe页面之间的通信问题

    最近项目中遇到一个与内嵌iframe页面之间通信的问题,起初与原生之间通信很简单,没想到过与vue项目通信的问题,霎时间一脸懵*啊,百度了一下,原来是那么简单,这里记录下以供下次参考 //vue页面 ...

  4. C# HttpClient使用和注意事项,.NET Framework连接池并发限制

    System.Net.Http.HttpClient 类用于发送 HTTP 请求以及从 URI 所标识的资源接收 HTTP 响应. HttpClient 实例是应用于该实例执行的所有请求的设置集合,每 ...

  5. Centos7部署rsync配合inotify进行系统文件实时备份

    转载csdn: Centos7部署rsync配合inotify进行系统文件实时备份_xixixilalalahaha的博客-CSDN博客

  6. Moonraker

    Moonraker 目录 Moonraker 1 信息收集 1.1 端口扫描 1.2 后台目录扫描 1.3 目录分析 1.3.1 /services/ 1.3.2 /svc-inq/salesmoon ...

  7. .net core Ubuntu下docker部署(精简版)

    一.首先先添加一个.netCore 项目,选择启用docker(我用的是vs2019,之前的可能需要手动点击项目添加docker支持) 没有的话需要手动添加 之后你的项目会存在这个dockerfile ...

  8. 路飞项目使用mysql数据库详细讲解

    目录 一.首先需要彻底删除原有的数据库步骤 二.去官网下载mysql步骤 三.安装mysql数据库步骤 四.一管理员身份进去cmd进行一系列命令启动 五.接下来为路飞项目创建数据库 六.luffy项目 ...

  9. ElasticSearch 实现分词全文检索 - 概述

    需求 做一个类似百度的全文搜索功能 所用的技术如下: ElasticSearch Kibana 管理界面 IK Analysis 分词器 SpringBoot ElasticSearch 简介 ES ...

  10. rust vec排序

    一.sort let mut v = vec![4,3,3,1,2]; println!("{:#?}",v); v.sort(); println!("{:#?}&qu ...