搜索
您的当前位置:首页正文

kvo填坑

来源:二三娱乐

最近两天时间比较充裕,然后这个月的工作安排也已经完成,所以拿点时间来对Cocoa一些问题填个坑,毕竟自己真的掉进去了啊!o(╯□╰)o

起因也是那天同事要实现一个垮多对象之间的数据传递,然后我就说可以用kvo啊(话说我也用的不多,就这样把别人带进去了),然后就是他就掉坑里了,发现对一个属性类型为 NSArray 做keyValuePath (eg:“prop.count”) 根本无法监控到改数组发生改变,原因是 用错了方法,针对数组,应该使用

 - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key; 

因为监控的是setter 方法,只有在对属性赋值 prop = "pro"的前后,分别调用 willChangeValueForKey: 和 didChangeValueForKey: ,才会触发通知。那个坑就这么填完了!

为了以后少坑自己,所以今天对kvo多做了一些了解,就稍微记录下!
先上图:

kvo原理流程

就拿人来说事吧

@interface Persion :NSObject
@property(nonatomic,assign) age;
@property(nonatomic,copy) name;
@end

然后在 Person 实例对象添加了一个观察者

Person *hecv = [Person new];
[hecv addObserver:observer forKeyPath:@"age" options:0 context:NULL];

当这个 Person对象被第一次添加观察者的时候,其实他派生了一个类 SubPerson,(Person和Subperson 都是类对象,不是对应的实例),这个派生类在实现上,发生了一些变化;

  • 重写了类对象的 class 方法,让他自己的isa 指针指向 父类的isa指针指向的地址。目的是欺骗外部调用者,让他们以为本派生类就是基类,这个实现有说是系统处理的。
  • 重写了父类所有被观察的 setter 方法,这里来说就是 setage: 方法。
    目的是在外部调用 Person实例对象的 setter 方法的时候,其实他找的类对象,并不是原来的 Person类对象,而是subPerson 类对象,(这个对象有点特殊,类名应该是 NSKVONotifying_Person) ,从而在setter 方法中可以通过 willChangeValueForKey: 和didChangeValueForKey: 两个方法来监控属性的变化。
  • dealloc 方法用来处理内存问题
  • _isKVOA 这个私有方法应该是用来表示这个类对象是KVO的

个人的理解大概就是这么多了,苹果的官方 programming guid 是这样描述的。

官方kvo实现细节说明

所以总的来说哦,kvo这个东西是基于强大的runtime的好技术,应该说是语言的所带来的产品吧!

对博文中的一些不太理解的问题做了分析,可能因为对runtime的一些理解并不透彻,造成偏颇,看客请轻拍砖和指正!要更好的理解,请细读楼上链接的博文!

Top