KVC,KVO,通知
2016-02-16 15:57
239 查看
KVO就是键值观察
KVC就是键值编码, 间接访问对象实例变量的方式, 该机制可以不通过存取方法就可以访问对象的实例变量.
KVO 是建立在 KVC的基础上的, 在KVO中必须使用键值编码才能修改他的实例变量.
手动实现kvo: http://tech.glowing.com/cn/implement-kvo/
http://blog.sunnyxx.com/2014/03/09/objc_kvo_secret/
举个KVO的例子 :
- (void)viewDidLoad {
[superviewDidLoad];
UIButton *btn = [[UIButtonalloc]initWithFrame:CGRectMake(100,500,100,100)];
self.btn = btn;
btn.backgroundColor = [UIColorredColor];
[self.viewaddSubview:btn];
KVO用来监听属性的变化,有人改变了btn的属性,我就会监听到
只要item的forKeyPath监听的值改变了,addObserver就会监听到(调用self的一个方法进行监听的操作)
[btn addObserver:@"注册的所要监控的对象(观察者, 负责处理监听事件的对象, 我监控btn的属性的变化)" forKeyPath:@"所要监控的属性"
options:@"观察的选项 (观察什么的变化(比如
NSKeyValueObservingOptionNew和NSKeyValueObservingOptionOld))" context:@"传递给监控者的任意数据"];
//添加键值观察
1. 观察者, 负责处理监听事件的对象
2. 观察的属性
3. 观察的选项
4. 上下文
[btn addObserver:self forKeyPath:@"highlighted"
options:NSKeyValueObservingOptionNew context:@"test_Button"];
}
//所有KVO监听到事件,
都要调用下面的方法
1. 观察的属性
2. 观察的对象
3. change 属性变化字典
4. 上下文, 与监听的时候传递的一致
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString
*,id> *)change context:(void *)context {
//防止注册了多个KVO的这种情况
if((self.btn == object) && ([keyPathisEqualToString:@"highlighted"]))
{
NSLog(@"keyPath= %@, object= %@, change= %@, context= %@", keyPath, object, change, context);
} else {
//
有可能绑定的是父类的KVO
[super
observeValueForKeyPath:keyPath ofObject:objectchange:changecontext:context];
}
}
-(void)dealloc {
// test_Button,防止父类释放了,自己又释放而引起的奔溃问题.
[self.btn removeObserver:self forKeyPath:@"highlighted" context:@"test_Button"];
}
我写的不清楚的地方, 可以参考: http://www.cnblogs.com/wengzilin/p/4346775.html
KVC:
1. setValue: forKey 只能设置属性,实例变量
2. setValue: forKeyPath 可以对他们的路径进
12976
行设置 @"btn.highlighted"
3. KVC 的本质就是查找属性,实例变量,通过isa指针去查找(isa会告诉系统这个对象的类是什么). 先在子类, 再在父类, 如果最终没有找到这个属性, 就检查有没有实现btn setValue: forUndefinedKey:这个方法, 如果没有实现,就会奔溃.
4. KVC的本质就是遍历字典中所有的key, 去模型中查找对应的属性, 然后把值赋给模型属性
[dict enumerateKeysAndObjectsUsingBlock:
^(id _Nonnull key,id _Nonnull obj,BOOL
*_Nonnull stop) {
//这行代码才是真正给模型的属性赋值
[s setValue:dict[@"name"] forKey:@"name"];
查找过程: 首先在模型中查找有没有setName方法, 找到之后[s setName:dict[@"name"]]
找不到就在模型中寻找有没有name属性, 没有找到就寻找_name,
最后实在找不到就调用setValue:forUndefinedKey:方法, 如果没有实现此方法, 系统自动奔溃.
}];
KVO和通知的区别:
1)KVO:(Key Value Observing)
被观察者发出 addObserver:forKeyPath:options:context: 方法来添加观察者。
然后只要被观察者的keyPath值变化(注意:单纯改变其值不会调用此方法,只有通过getters和setters来改变值才会触发KVO),就会在观察者里调用方法observeValueForKeyPath:ofObject:change:context:
因此观察者需要实现方法 observeValueForKeyPath:ofObject:change:context: 来对KVO发出的通知做出响应。
这些代码都只需在观察者里进行实现,被观察者不用添加任何代码,所以谁要监听谁注册,然后对响应进行处理即可,使得观察者与被观察者完全解耦,运用很灵活很简便;但是KVO只能检测类中的属性,并且属性名都是通过NSString来查找,编译器不会帮你检错和补全,纯手敲所以比较容易出错,最好用宏定义。
2)NSNotification这里的通知不是由被观察者发出,而是由NSNotificationCenter来统一发出,而不同通知通过唯一的通知标识名notificationName来区分,标识名由发送通知的类来起。首先被观察者自己在必要的方法A里,通过方法postNotificationName:object:来发出通知notificationName这样发送通知者这边的工作就完成了,每次A被调用,就会发送一次通知notificationName。然后谁要监听A的变化,就通过[NSNotificationCenterdefaultCenter]的方法addObserver:selector:name:object:为观察者注册监听name为notificationName的通知然后每次发出name为notificationName的通知时,注册监听后的观察者就会调用其自己定义的方法notificationSelector来进行响应。
NSNotification的特点呢,就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。
通知的使用
1. 必须先监听通知
2. 然后发送通知, 只要是一个频道, 就都是可以监听到通知.
?
3. 通知传值
发送通知, 将要传递的数值包装成一个字典, 传递过去.
如果我们要传递一个对象, 直接在object后面传递数据就可以了; 如果要传递很多组数据, 那就在userInfo后面传递就行了
NSNotification *notification =[NSNotification notificationWithName:@"PJBaseSelectView" object:nil userInfo:@{@"PJMe":model,@"PJMeFlag":STRING_Int(0)}];
[[NSNotificationCenter defaultCenter] postNotification:notification];
接收通知, 接收到数值之后, 再解析出字典里面的数值
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tongzhiBaseSelect:) name:@"PJBaseSelectView" object:nil];
- (void)tongzhiBaseSelect:(NSNotification *)text {
PJLog(@"%@", text);
NSString *flagValue = text.userInfo[@"PJMeFlag"];
HTHotSearchModel *model = text.userInfo[@"PJMe"];
}
KVO实现
这是怎么实现的呢?其实这都是通过Objective-C强大的运行时(runtime)实现的。当你第一次观察某个object 时,runtime会创建一个新的继承原先class的subclass。在这个新的class中,它重写了所有被观察的key,然后将object的isa指针指向新创建的class(这个指针告诉Objective-C运行时某个object到底是哪种类型的object)。所以object神奇地变成了新的子类的实例。
这些被重写的方法实现了如何通知观察者们。当改变一个key时,会触发setKey方法,但这个方法被重写了,并且在内部添加了发送通知机制。(当然也可以不走setXXX方法,比如直接修改iVar,但不推荐这么做)。
有意思的是:苹果不希望这个机制暴露在外部。除了setters,这个动态生成的子类同时也重写了-class方法,依旧返回原先的class!如果不仔细看的话,被KVO过的object看起来和原先的object没什么两样。
KVC就是键值编码, 间接访问对象实例变量的方式, 该机制可以不通过存取方法就可以访问对象的实例变量.
KVO 是建立在 KVC的基础上的, 在KVO中必须使用键值编码才能修改他的实例变量.
手动实现kvo: http://tech.glowing.com/cn/implement-kvo/
http://blog.sunnyxx.com/2014/03/09/objc_kvo_secret/
举个KVO的例子 :
- (void)viewDidLoad {
[superviewDidLoad];
UIButton *btn = [[UIButtonalloc]initWithFrame:CGRectMake(100,500,100,100)];
self.btn = btn;
btn.backgroundColor = [UIColorredColor];
[self.viewaddSubview:btn];
KVO用来监听属性的变化,有人改变了btn的属性,我就会监听到
只要item的forKeyPath监听的值改变了,addObserver就会监听到(调用self的一个方法进行监听的操作)
[btn addObserver:@"注册的所要监控的对象(观察者, 负责处理监听事件的对象, 我监控btn的属性的变化)" forKeyPath:@"所要监控的属性"
options:@"观察的选项 (观察什么的变化(比如
NSKeyValueObservingOptionNew和NSKeyValueObservingOptionOld))" context:@"传递给监控者的任意数据"];
//添加键值观察
1. 观察者, 负责处理监听事件的对象
2. 观察的属性
3. 观察的选项
4. 上下文
[btn addObserver:self forKeyPath:@"highlighted"
options:NSKeyValueObservingOptionNew context:@"test_Button"];
}
//所有KVO监听到事件,
都要调用下面的方法
1. 观察的属性
2. 观察的对象
3. change 属性变化字典
4. 上下文, 与监听的时候传递的一致
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString
*,id> *)change context:(void *)context {
//防止注册了多个KVO的这种情况
if((self.btn == object) && ([keyPathisEqualToString:@"highlighted"]))
{
NSLog(@"keyPath= %@, object= %@, change= %@, context= %@", keyPath, object, change, context);
} else {
//
有可能绑定的是父类的KVO
[super
observeValueForKeyPath:keyPath ofObject:objectchange:changecontext:context];
}
}
-(void)dealloc {
// test_Button,防止父类释放了,自己又释放而引起的奔溃问题.
[self.btn removeObserver:self forKeyPath:@"highlighted" context:@"test_Button"];
}
我写的不清楚的地方, 可以参考: http://www.cnblogs.com/wengzilin/p/4346775.html
KVC:
1. setValue: forKey 只能设置属性,实例变量
2. setValue: forKeyPath 可以对他们的路径进
12976
行设置 @"btn.highlighted"
3. KVC 的本质就是查找属性,实例变量,通过isa指针去查找(isa会告诉系统这个对象的类是什么). 先在子类, 再在父类, 如果最终没有找到这个属性, 就检查有没有实现btn setValue: forUndefinedKey:这个方法, 如果没有实现,就会奔溃.
4. KVC的本质就是遍历字典中所有的key, 去模型中查找对应的属性, 然后把值赋给模型属性
[dict enumerateKeysAndObjectsUsingBlock:
^(id _Nonnull key,id _Nonnull obj,BOOL
*_Nonnull stop) {
//这行代码才是真正给模型的属性赋值
[s setValue:dict[@"name"] forKey:@"name"];
查找过程: 首先在模型中查找有没有setName方法, 找到之后[s setName:dict[@"name"]]
找不到就在模型中寻找有没有name属性, 没有找到就寻找_name,
最后实在找不到就调用setValue:forUndefinedKey:方法, 如果没有实现此方法, 系统自动奔溃.
}];
KVO和通知的区别:
1)KVO:(Key Value Observing)
被观察者发出 addObserver:forKeyPath:options:context: 方法来添加观察者。
然后只要被观察者的keyPath值变化(注意:单纯改变其值不会调用此方法,只有通过getters和setters来改变值才会触发KVO),就会在观察者里调用方法observeValueForKeyPath:ofObject:change:context:
因此观察者需要实现方法 observeValueForKeyPath:ofObject:change:context: 来对KVO发出的通知做出响应。
这些代码都只需在观察者里进行实现,被观察者不用添加任何代码,所以谁要监听谁注册,然后对响应进行处理即可,使得观察者与被观察者完全解耦,运用很灵活很简便;但是KVO只能检测类中的属性,并且属性名都是通过NSString来查找,编译器不会帮你检错和补全,纯手敲所以比较容易出错,最好用宏定义。
2)NSNotification这里的通知不是由被观察者发出,而是由NSNotificationCenter来统一发出,而不同通知通过唯一的通知标识名notificationName来区分,标识名由发送通知的类来起。首先被观察者自己在必要的方法A里,通过方法postNotificationName:object:来发出通知notificationName这样发送通知者这边的工作就完成了,每次A被调用,就会发送一次通知notificationName。然后谁要监听A的变化,就通过[NSNotificationCenterdefaultCenter]的方法addObserver:selector:name:object:为观察者注册监听name为notificationName的通知然后每次发出name为notificationName的通知时,注册监听后的观察者就会调用其自己定义的方法notificationSelector来进行响应。
NSNotification的特点呢,就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。
通知的使用
1. 必须先监听通知
?
发送通知, 将要传递的数值包装成一个字典, 传递过去.
如果我们要传递一个对象, 直接在object后面传递数据就可以了; 如果要传递很多组数据, 那就在userInfo后面传递就行了
NSNotification *notification =[NSNotification notificationWithName:@"PJBaseSelectView" object:nil userInfo:@{@"PJMe":model,@"PJMeFlag":STRING_Int(0)}];
[[NSNotificationCenter defaultCenter] postNotification:notification];
接收通知, 接收到数值之后, 再解析出字典里面的数值
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tongzhiBaseSelect:) name:@"PJBaseSelectView" object:nil];
- (void)tongzhiBaseSelect:(NSNotification *)text {
PJLog(@"%@", text);
NSString *flagValue = text.userInfo[@"PJMeFlag"];
HTHotSearchModel *model = text.userInfo[@"PJMe"];
}
KVO实现
这是怎么实现的呢?其实这都是通过Objective-C强大的运行时(runtime)实现的。当你第一次观察某个object 时,runtime会创建一个新的继承原先class的subclass。在这个新的class中,它重写了所有被观察的key,然后将object的isa指针指向新创建的class(这个指针告诉Objective-C运行时某个object到底是哪种类型的object)。所以object神奇地变成了新的子类的实例。
这些被重写的方法实现了如何通知观察者们。当改变一个key时,会触发setKey方法,但这个方法被重写了,并且在内部添加了发送通知机制。(当然也可以不走setXXX方法,比如直接修改iVar,但不推荐这么做)。
有意思的是:苹果不希望这个机制暴露在外部。除了setters,这个动态生成的子类同时也重写了-class方法,依旧返回原先的class!如果不仔细看的话,被KVO过的object看起来和原先的object没什么两样。
相关文章推荐
- Android事件分发机制学习和总结
- Windows Azure Application Gateway 应用程序网关
- php计算两个经纬度地点之间的距离
- 【shiro】shiro学习笔记3-散列功能
- 对路径“C:\Program Files (x86)\test\test.txt”的访问被拒绝 C#
- linux小白学习笔记(二)设备文件
- Linux下的I/O复用与epoll详解 - junren
- Android 复制文本代码段
- 【方便查】git bash命令(仓库内)
- Java socket参数keepalive
- c++模板的特化和偏特化
- JQuery 鼠标hover不停闪动的问题
- [LeetCode 088] Merge Sorted Array
- mysql update from
- [Dev]DevExpress之treelist右键菜单实现
- ActiveMQ持久化方式--ActiveMQ入门之三
- 为知笔记 Markdown 新手指南
- Python基础篇【第2篇】: Python文件操作
- 1812
- 【方便查】git bash命令(仓库外)