博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
KVO 键值观察
阅读量:7111 次
发布时间:2019-06-28

本文共 4387 字,大约阅读时间需要 14 分钟。

1、KVO

  • KVO 是 Key-Value Observing 的简写,是键值观察的意思,属于 runtime 方法。Key Value Observing 顾名思义就是一种 observer 模式用于监听属性变量值的变化,也是运行时的方法,当实例变量改变时,系统会自动采取一些动作。KVO 跟 NSNotification 有很多相似的地方,用 addObserver:forKeyPath:options:context: 去 start observer, 用 removeObserver:forKeyPath:context 去 stop observer, 回调就是 observeValueForKeyPath:ofObject:change:context:。
  • 对于 KVO 来说,我们要做的只是简单 update 我们的 property 的数据,不需要像 NSNotificationCenter 那样关心是否有人在监听你的请求,如果没有人监听该怎么办,所有 addObserver, removeObserver, callback 都是想要监听的你的 property 的 class 做的事情。曾经做个项目,用 NSNotificationCenter post Notification 在一个 network callback 里面,可是这时候因为最早的 addObserver 的 class 被释放了,接着生成的 addObserver 的 class, 就接受到了上一个 observer 该监听的事件,所以造成了错误,那时候的解决方案是为 addObserve key 做 unique,不会 2 次 addObserver 的 key 是相同的,但是有了 KVO, 我们同样可以用 KVO 来完成,当 addOberver 的的 object remove 的时候,就不会有这样的 callback 被调用了。
  • KVO 给我们提供了更少的代码,和 NSNotification 比好处,不需要修改被观察的 class, 永远都是观察你的人做事情。 但是 KVO 也有些毛病:
    • 1、如果没有 observer 监听 keyPath, removeObsever:forKeyPath:context: 这个 keyPath, 就会 crash(崩溃), 不像 NSNotificationCenter removeObserver。
    • 2、对代码你很难发现谁监听你的 property 的改动,查找起来比较麻烦。
    • 3、对于一个复杂和相关性很高的 class,最好还是不要用 KVO, 就用 delegate 或者 notification 的方式比较简洁。
  • KVO 使用分三步:
    • 1、注册成为观察者。
    • 2、观察者定义 KVO 的回调。
    • 3、移除观察者。
  • KVO 使用注意:
    • KVO 是同步的,一旦对象的属性发生变化,只有用同步的方式,才能保证所有观察者的方法能够执行完成。KVO 监听方法中,不要有太耗时的操作。
    • KVO 的方法调用,是在对应的线程中执行的。在子线程修改观察属性时,观察者回调方法将在子线程中执行。
    • 在多个线程同时修改一个观察属性的时候,KVO 监听方法中会存在资源抢夺的问题,需要使用互斥锁。如果涉及到多线程,KVO 要特别小心,通常 KVO 只是做一些简单的观察和处理,千万不要搞复杂了,KVO的监听代码,一定要简单。
    • 一定要删除观察者,如果不删除观察者,释放对象,会直接崩溃。An instance 0x7fd340ebc400 of class KvoClass was deallocated while key value observers were still registered with it.

2、KVO 的使用

// KvoClass.h@interface KvoClass : NSObject@property(nonatomic, copy) NSString *name;@end// ViewController.m@property(nonatomic, retain) KvoClass *kvoObject;_kvoObject = [[KvoClass alloc] init];
  • 2.1 KVO 添加

    - (void)addObserver:(NSObject *)observer         forKeyPath:(NSString *)keyPath            options:(NSKeyValueObservingOptions)options            context:(nullable void *)context;public func addObserver(observer: NSObject,              forKeyPath keyPath: String,                         options: NSKeyValueObservingOptions,                         context: UnsafeMutablePointer
    )参数说明: 第一个参数 observer 是观察的类; 第二个参数 keyPath 是被观察的类中被观察的属性; 第三个参数 options 是观察选项; 第四个参数 context 是传递的上下文内容。// 添加观察者[_kvoObject addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"nameChange"];// 改变被观察的键对应的值_kvoObject.name = @"xiao bai";sleep(2);_kvoObject.name = @"xiao hei";
  • 2.2 KVO 回调

    - (void)observeValueForKeyPath:(nullable NSString *)keyPath                      ofObject:(nullable id)object                        change:(nullable NSDictionary
    *)change context:(nullable void *)context;public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer
    )参数说明: keyPath:监控的 key; object:被监控的对象的基本属性; change:被监控的对象的 key 对应的 value 值的变化(kind:类型,new:变化后的值,old:变化前的值。// 系统自带方法- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context == @"nameChange") { NSLog(@"name 值被改变 kind = %@, oldValue = %@, newValue = %@", change[@"kind"], change[@"old"], change[@"new"]); } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; }}
  • 2.3 KVO 移除

    • 在实际工作中需要在合适的时候移除观察者身份。
    NS_AVAILABLE(10_7, 5_0)- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context;- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;public func removeObserver(observer: NSObject, forKeyPath keyPath: String, context: UnsafeMutablePointer
    )public func removeObserver(observer: NSObject, forKeyPath keyPath: String)参数说明: 第一个参数 observer 是观察的类; 第二个参数 keyPath 是被观察的类中被观察的属性; 第三个参数 context 是传递的上下文内容。- (void)dealloc { // 移除观察者 [_kvoObject removeObserver:self forKeyPath:@"name" context:@"nameChange"];}

转载于:https://www.cnblogs.com/CH520/p/9514322.html

你可能感兴趣的文章
BCH正式升级,智能合约,逐梦而来!
查看>>
json-handle:json可视化工具
查看>>
Crypto++ 编码与哈希(StringSource和FileSource)
查看>>
c语言指针闲谈
查看>>
随记:Ubuntu12.04下手工配置网络
查看>>
微软整合实验(四):迁移FSMO操作主机角色,基于Server 2008 R2
查看>>
主从mysql遇到的问题,
查看>>
iptables 禁止端口和开放端口
查看>>
Linux软件包管理之rpm
查看>>
30. PowerShell -- 后台作业、异步操作实例
查看>>
libpcre.so.1: cannot open shared object file: No such file or directory
查看>>
记录方维p2p项目后台登录自动化测试验证码问题
查看>>
ubuntu 10 下vim 总是出现异常问题
查看>>
Linux系统管理与维护之-tar命令
查看>>
Excel统计时间段内工作日间的时间差
查看>>
Audio Unit Processing Graph
查看>>
Windows Server 2012 R2快速部署基于会话的VDI
查看>>
Maven的一些小配置(续)
查看>>
VB无所不能之四:制作透明和半透明窗体
查看>>
rhel6.0配置rsyslog传送日志到远程主机
查看>>