再探KVO
来源:互联网 发布:流程优化小组 编辑:程序博客网 时间:2024/06/05 20:03
KVO(Key-Value-Observing)键值观察
监听property的变化 通知某些对象(观察者)关于其他对象属性值发生变化的一种机制.
优缺点
优点
性能好[开销相对于NSNotification和委托更小(只用存取方法来修改实例变量,不需要额外成本)];
容易实现视图组件和数据模型的分离,模型类的简洁;
缺点
回调方法中传递的代表变化的字典,用起来繁琐;bug难解决(会制造出人意料的代码执行路径,有一些代码运行但没有任何可见的代码说明行为发生的原因);
DEMO
// from AFNetworking--AFURLSessionManager// 添加监听对象(注册指定key路径的监听器)[task addObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived)) options:NSKeyValueObservingOptionNew context:NULL];// 移除监听对象(删除指定keyPath的监听器)[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))];// 回调监听- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) { if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) { self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue]; } // ...}
最佳实践
尽量保守,简单的使用KVO; 在存在复杂相互依赖关系或者复杂的类继承层次的地方避免使用.
– 9th,August,2016
注册键值依赖
// from AFNetworking+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) { return [NSSet setWithObject:@"networkReachabilityStatus"]; } return [super keyPathsForValuesAffectingValueForKey:key];}+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; if ([key isEqualToString:@"fullName"]) { NSArray *affectingKeys = @[@"lastName", @"firstName"]; keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys]; } return keyPaths;}
Tips
– 5th,April,2017
添加移除位置
UIViewController中在viewWillAppear中添加键值观察,在viewWillDisappear中移除键值观察。或者init与dealloc中添加和移除键值观察。
UIView在awakeFromNib中添加键值观察,在removeFromSuperview中移除键值观察。
ps: 如果在不恰当的地方(比如UIView中在willRemoveSubview中)移除可能会导致崩溃“Cannot remove an observer because it is not registered as an observer.”,也不可在ViewDidDisappear中移除,比如在B页面的ViewDidDisappear中移除通知,页面跳转逻辑为A->B->C,B跳到C页面调用一次,B返回A页面调用一次,就会出现崩溃问题。
无法接收到观察通知:
一般就3个理由,1) 添加键值观察时对象为空;2) 通知已经发送,然后才添加的键值观察; 3)添加键值观察的对象被销毁,比如为weak或其他情况导致无法接收。
参考资料
log
5th,April,2017 – add Tips2
25th,October,2015
- 再探KVO
- KVO
- kvo
- kvo
- KVO
- KVO
- Kvo
- KVO
- kvo
- KVO
- KVO
- KVO
- KVO
- KVO
- KVO
- KVO
- KVO
- KVO
- curl各命令参数详解
- Vtk与opencv的冲突
- 吞吐量(Throughput)、QPS、并发数、响应时间(RT)
- Lua中的闭包
- Android获取当前城市名称
- 再探KVO
- java反射机制之Method invoke执行调用方法例子
- 【机器学习PAI实践三】雾霾成因分析
- Android API官方文档 存储选项
- 关于XML的解析的问题
- 2015蓝桥杯省赛模拟题C组
- Android菜单的使用
- 关于jsp中的tablib标签的定义与使用
- @JoinColumn 与mappedBy