https://blog.csdn.net/crayondeng/article/details/18842395
kvo是键值观察的缩写,是一种观察者模式。
它较完美地将目标对象与观察者对象解耦。
1, 依赖键,
依赖键的setter方法被调用了之后, 观察者也能得到通知。
原有的setter方法修改了,也能得到通知。
2 ,通知回调中的字典,
变更前的值,变更后的值NSKeyValueObservingOptionNew, NSKeyValueObservingOptionOld
{"kind":1,"old":"23456","new":"23456"}
什么都不加,则字典中无法得到值
{"kind":1}
3, 通知被回调次数
变更之前调用1次
{"kind":1,"old":null,"notificationIsPrior":true} 变更之前。 只有old
变更之后调用1次
{"kind":1,"old":null,"new":"23456"} 变更之后,old和new都有
4, 是如何触发了通知得到回调的
willChangeValueForKey调用之后调用{"kind":1,"old":null,"notificationIsPrior":true}
didChangeValueForKey调用之后调用{"kind":1,"old":null,"new":"23456"}
setter方法自动增加了willChangeValueForKey和didChangeValueForKey
如果是手动触发,就需要手动调用willChangeValueForKey,didChangeValueForKey
[self willChangeValueForKey:@"helloString"];
[self setHelloString:@"23456"];
[self didChangeValueForKey:@"helloString"];
5, 通知回调所在的线程,
在哪个线程触发的,就在哪个线程执行回调方法observeValueForKeyPath
默认setter中的willChangeValueForKey, 和didChangeValueForKey的触发是单线程同步的方式运行
6,原理
http://blog.sunnyxx.com/2014/03/09/objc_kvo_secret/
1,当一个object有观察者时,动态创建这个object的类的子类。 重新写class方法,返回原来的类。 但是isa已经是新的类了。
增加了_isKVOA方法。
谁被观察了,谁就被isa swizzle了
keypath如果是多层级的,则.前面的对象的类也被isa swizzle
2,对于每个被观察的property,重写其set方法===================不对啊。 私有变量并且accessInstanceVariablesDirectly返回NO,返回YES。都没有setter方法。
3,在子类中 重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者====== 应该是重写了 willChangeValueForKey 和didchangeValueforkey 通知观察者的。
property合成的方法。 2,3合适。子类中 确实是重写了 setter方法
4,当一个property没有观察者时,删除重写的方法
5,当没有observer观察任何一个property时,删除动态创建的子类
7,将观察者对象与被观察者对象进行注册与解除注册:
在dealloc中需要接触注册,否则崩溃
问题来了,为什么会崩溃?
8,kvc 变量能不能引发KVO? 能
kvc 只读变量能不能引发KVO? 能
变量的直接赋值能不能引发KVO? 不能
kvc 顺序; 先方法,后实例
读
1、getkey key iskey方法
2、_key,_iskey,key, iskey实例
3、valueforUndefinedKey
写
1、setkey,setnilvalueforkey 类型不是对象类型则崩溃
2、_key,_iskey,key,iskey实例
3、setvalue:forundefinedkey:未定义的
9, [obj addObserver:forKeyPath:options:context:] 参数的意义
obj : 被观察的对象;
谁被观察了,谁就被isa swizzle了;
keypath如果是多层级的,则.前面的对象的类也被isa swizzle
observer :观察者,就是实现了observeValueForKeyPath:ofObject:change:context:的
forkeypath: 被观察的对象的属性或者私有变量的key名字,符合kvc搜索路径(属性自动合成了实例变量。非属性:私有实例变量);如果是keypath,则keypath的每一级变化对能导致kvo发生。
options: 配置;1、回调次数,2、回调方法中change是否带有值,是否有old值/new值 3、是否addobserver后立即调用kvo的回调
context: 传递给观察者的任意数据
// 误解的写法。不是错误,只是观察者是self.model,由self.model的类实现通知回调的方法。
//这句的意思观察者是self.model,self.model需要实现kvo回调方法。 被观察的对象是self,观察的keypath是self的string。 所以当被观察者self存在string属性,string变化了,观察者self.model的kvo回调方法得到回调
[self addObserver:self.model forKeyPath:@"string" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew|NSKeyValueObservingOptionPrior context:nil];
//支持,跟RACObserve(self.model, string)相同
///观察者是self,被观察的对象是self.model,观察的keypath是string。当被观察者self.model存在string属性, string变化了,观察者self的kvo回调方法得到回调
[self.model addObserver:self forKeyPath:@"string" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew|NSKeyValueObservingOptionPrior context:nil];
//支持,跟RACObserve(self,model.string)相同
//观察者是self,被观察的对象是self,观察的keypath是model.string。当被观察者self存在model属性,model存在string属性。 model.string变化了,或者model变化了,kvo回调都会执行,change字典中的值keypath路径中最后一个属性的值。
//model 和self的类都被重写
[self addObserver:self forKeyPath:@"model.string" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew|NSKeyValueObservingOptionPrior context:nil];
网友评论