Swift中使用KVO
在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定义的属性,必须在属性前添加@objc和dynamic修饰才可以,否则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的更多相关文章
- how to use kvo with swift (怎样在swift中使用kvo)
- 一览Swift中的常用关键字
要学习Swift这门语言,就必须先了解Swift的关键字及对应的解释.这里就列一下在Swift中常用到的关键字. 关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符 ...
- Swift 中枚举
Swift 中枚举高级用法及实践 字数11017 阅读479 评论0 喜欢20 title: "Swift 中枚举高级用法及实践"date: 2015-11-20tags: [AP ...
- Combine 框架,从0到1 —— 4.在 Combine 中使用 KVO
本文首发于 Ficow Shen's Blog,原文地址: Combine 框架,从0到1 -- 4.在 Combine 中使用 KVO. 内容概览 前言 用 KVO 监控改动 将 KVO 代 ...
- swift 中关于open ,public ,fileprivate,private ,internal,修饰的说明
关于 swift 中的open ,public ,fileprivate,private, internal的区别 以下按照修饰关键字的访问约束范围 从约束的限定范围大到小的排序进行说明 open,p ...
- 阿里巴巴最新开源项目 - [HandyJSON] 在Swift中优雅地处理JSON
项目名称:HandyJSON 项目地址:https://github.com/alibaba/handyjson 背景 JSON是移动端开发常用的应用层数据交换协议.最常见的场景便是,客户端向服务端发 ...
- Swift中的可选链与内存管理(干货系列)
干货之前:补充一下可选链(optional chain) class A { var p: B? } class B { var p: C? } class C { func cm() -> S ...
- 在Swift中实现单例方法
在写Swift的单例方法之前可以温习一下Objective-C中单例的写法: + (instancetype)sharedSingleton{ static id instance; static d ...
- [翻译]理解Swift中的Optional
原文出处:Understanding Optionals in Swift 苹果新的Swift编程语言带来了一些新的技巧,能使软件开发比以往更方便.更安全.然而,一个很有力的特性Optional,在你 ...
- 窥探Swift之使用Web浏览器编译Swift代码以及Swift中的泛型
有的小伙伴会问:博主,没有Mac怎么学Swift语言呢,我想学Swift,但前提得买个Mac.非也,非也.如果你想了解或者初步学习Swift语言的话,你可以登录这个网站:http://swiftstu ...
随机推荐
- Visual Studio更改项目文件夹名称
一.VS打开项目解决方案(按以下顺序操作) PS:如果已经出错,打不开.sln文件,就从第三步开始操作,进入目录更改对应其.csproj文件名称即可 1.选择要更改的项目或类库,右键属性,更改程序集名 ...
- servlet传入多个数据
通过&来传入值:<a href="bookquery?page=1&nameBook=&author=&publisher=>1</a> ...
- 关于vue项目和内嵌iframe页面之间的通信问题
最近项目中遇到一个与内嵌iframe页面之间通信的问题,起初与原生之间通信很简单,没想到过与vue项目通信的问题,霎时间一脸懵*啊,百度了一下,原来是那么简单,这里记录下以供下次参考 //vue页面 ...
- C# HttpClient使用和注意事项,.NET Framework连接池并发限制
System.Net.Http.HttpClient 类用于发送 HTTP 请求以及从 URI 所标识的资源接收 HTTP 响应. HttpClient 实例是应用于该实例执行的所有请求的设置集合,每 ...
- Centos7部署rsync配合inotify进行系统文件实时备份
转载csdn: Centos7部署rsync配合inotify进行系统文件实时备份_xixixilalalahaha的博客-CSDN博客
- Moonraker
Moonraker 目录 Moonraker 1 信息收集 1.1 端口扫描 1.2 后台目录扫描 1.3 目录分析 1.3.1 /services/ 1.3.2 /svc-inq/salesmoon ...
- .net core Ubuntu下docker部署(精简版)
一.首先先添加一个.netCore 项目,选择启用docker(我用的是vs2019,之前的可能需要手动点击项目添加docker支持) 没有的话需要手动添加 之后你的项目会存在这个dockerfile ...
- 路飞项目使用mysql数据库详细讲解
目录 一.首先需要彻底删除原有的数据库步骤 二.去官网下载mysql步骤 三.安装mysql数据库步骤 四.一管理员身份进去cmd进行一系列命令启动 五.接下来为路飞项目创建数据库 六.luffy项目 ...
- ElasticSearch 实现分词全文检索 - 概述
需求 做一个类似百度的全文搜索功能 所用的技术如下: ElasticSearch Kibana 管理界面 IK Analysis 分词器 SpringBoot ElasticSearch 简介 ES ...
- rust vec排序
一.sort let mut v = vec![4,3,3,1,2]; println!("{:#?}",v); v.sort(); println!("{:#?}&qu ...