简单概述
- KVO :
Key Value Observing
,针对继承自NSObject
的对象默认都遵循KVO,即事件通知机制(可以观察属性的变化)
使用很简单
- 添加观察者
bserveValueForKeyPath:ofObject:change:context:
- 监听回调
observeValueForKeyPath:ofObject: change: context:
- 移除观察者
removeObserver: forKeyPath:
看demo
Model类中随便写了属性
@property (nonatomic, strong) NSDictionary *dic;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
我们观察name
和dic
-首先我们实现自动发送
-我们ToOther
按钮弹出小窗口,监测name
变化
- (IBAction)toOtherVC:(id)sender {
self.otherVC.mo = self.mo;
self.mo.name = @"我是name";
[self presentViewControllerAsSheet:_otherVC];
}
-我们点击Pop
按钮监测dic
变化
- (IBAction)changeDicValue:(id)sender {
self.mo.dic = [NSDictionary dictionaryWithObject:@"我是dic" forKey:@"dic"];
[self dismissController:self];
}
注意谁观察谁注册!!!
// KVO 针对继承NSObject,添加观察者
[self.mo addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
[self.mo addObserver:self forKeyPath:@"dic" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
监听
/// 当属性发生改变时自动调用此方法
/// @param keyPath 观察的属性
/// @param object 被观察对象
/// @param change 字典里面存储的新值老值,跟添加观察者的对应
/// @param context 自定义添加观察者对象时添加的文本
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString: @"name"]) {
NSLog(@"%@===name",self.mo.name);
dispatch_async(Mainquene, ^{
self.TF.stringValue = self.mo.name;
});
}
else if ([keyPath isEqualToString:@"dic"]) {
NSLog(@"%@===dic",self.mo.dic);
dispatch_async(Mainquene, ^{
self.TF.stringValue = self.mo.dic[@"dic"];
});
}else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
手动控制KVO
以name属性为例
现在将name
自动发送通知设置为NO
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if ([key isEqualToString:@"name"]) {
return NO;
} else return YES;
}
此时会发现,就不会被监听到了,此时可以充血setter方法来实现,name赋值必须放在willChangeValueForKey
和didChangeValueForKey
中间,不放中间的话,自己打断点去测,它第一次的值是不准的。
[self willChangeValueForKey:@"name"];
_name = name;
[self didChangeValueForKey:@"name"];
}
如果你重写了setter
方法,却没有实现上面两个方法,也是不会监听的。
总结一句话willChangeValueForKey
和didChangeValueForKey
只有在automaticallyNotifiesObserversForKey
return NO
的时候才有效,不然只要注册观察者了,无论重写还是没重写setter
都会被监听
如有不对还忘指出