kvo:key-value-observing:键值监听,可以监听某个对象属性的值
前言
使用(kvo 监听food属性,使用self.food也可以监听到)
注意:当监听Dog时候,在工程中创建NSKVONotifying_Dog类打印台提示以下,并且监听不起作用
[general] KVO failed to allocate class pair for name NSKVONotifying_Dog, automatic key-value observing will not work for this class
NSLog(@"%@,%@",[dog1 class],[dog2 class]);
// 打印结果 Dog, Dog
//我们可以猜测NSKVONotifyin_ Dog内重写的class内部实现大致为
- (Class) class {
// 得到类对象,在找到类对象父类
return class_getSuperclass(object_getClass(self));
}
如果NSKVONotifyin_Dog不重写class方法,那么当对象要调用class对象方法的时候就会一直向上找来到NSObject,而NSObject的class的实现大致为返回自己isa指向的类,返回p1的isa指向的类那么打印出来的类就是NSKVONotifyin_Dog,但是apple不希望将NSKVONotifyin_Dog类暴露出来,并且不希望我们知道NSKVONotifyin_Dog内部实现,所以在内部重写了class类,直接返回Person类,所以外界在调用dog1的class对象方法时,是Dog类。这样dog1给外界的感觉dog1还是Dog类,并不知道NSKVONotifyin_Dog子类的存在。

@interface ViewController ()
@property (nonatomic,strong)Dog *dog1;
@property (nonatomic,strong)Dog *dog2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dog1 = [Dog new];//此时 po self.dog1.->isa Dog
self.dog2 = [Dog new];
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld;
[self.dog1 addObserver:self forKeyPath:@"food" options:options context:@"Steven"];
//此时 po self.dog1.->isa NSKVONotifying_Dog
// [self.dog1 removeObserver:self forKeyPath:@"food" context:@"steven"];//此时 po self.dog1.->isa Dog
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//会触发observeValueForKeyPath的方式
//方式一:.语法常规操作
self.dog1.food = @"gutou";
self.dog2.food = @"shi";
//方式二:直接调用set方法
[self.dog1 setFood:@"gutou"];
//方式三:配对(必须配对)调用willChangeValueForKey didChangeValueForKey
[self.dog1 willChangeValueForKey:@"food"];
[self.dog1 didChangeValueForKey:@"food"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"\nobject:%@\nkeyPath:%@\nchange:%@\ncontext:%@",object, keyPath, change, context);
}
@end
面试题:
1:ios用什么方式实现对一个对象的kvo?(kvo的本质是什么?)
利用runtimeAPI动态生成一个子类,并让instance对象的isa指向这个全新的类,当修改instance对象的属性时,会调用Foundation的——NSSetXXXValueAndNotify函数:(willChangeValueForKey; 父类原来的setter方法;didChangeValueForKey(内部会触发监听器(observer)的监听方法(observerValueForKeyPath:)),)
2:如何手动触发kvo?
(不调用setage方法)
手动调用willChangeValueForKey 和didChangeValueForKey方法,即可直接触发kvo。
3:直接修改成员变量会触发KVO么?
不会触发KVO,(添加kvo的person实例,其实是NSKVONotyfing_person类,再调用setter方法,不是调用person的setter方法,而是NSKVONotyfing_person的setter方法,因为修改成员变量不是setter方法赋值self.person->age=@"12", 所以就无所谓调用NSKVONotyfing_person类的setter方法,也就不会实现kvo。)



网友评论