KVOController原理解析
1、使用类似动态代理的模式和消息派发中枢模式实现整个架构;
2、使用NSMapTable和NSHashTable进行切面信息的增删查维护;主要用于去重和查看是否存在。
实现方式
消息流
KVOControllerKVOControllerUML
observer 调用的方法注册观察者。
- FBKVOController 处理观察者信息,并将其封装为_FBKVOInfo。过滤重复的或者未注册过的观察消息。定义如下:
@interface _FBKVOInfo : NSObject - @end
- @implementation _FBKVOInfo {
- @public
- __weak FBKVOController *_controller;
- NSString *_keyPath;
- NSKeyValueObservingOptions _options;
- SEL _action;
- void *_context;
- FBKVONotificationBlock _block;
- }
_FBKVOInfo FBKVOController _FBKVOInfo _FBKVOInfo crashFBKVOController 调用中转站的方法。- _FBKVOSharedController 向完成真正的观察者注册。
- 关注的发生改变时,向发送通知。
- _FBKVOSharedController _FBKVOInfo observerobserver 与为一一对应关系,即一个观察者实例对应一个实例,而所有的观察者注册和回调工作都有这个单例完成,其将在软件的整个生命周期内存活。
弱引用
KVOController @interface FBKVOController : NSObject
@property (atomic, weak, readonly) id observer;
@end
@implementation FBKVOController
- (void)dealloc {
[self unobserveAll];
}
@end
KVOController 维护了一个对观察者的弱引用。
- KVOController 释放时会移除其注册的观察者消息。
_FBKVOInfo FBKVOController KVOController KVOController KVOController 消息过滤
KVOController 如下所示,为 FBKVOController 的 observe 代码片段,通过可知,首先判断是否已经包含对应观察者消息,如果包含则直接返回。
- (void)_observe:(id)object info:(_FBKVOInfo *)info {
OSSpinLockLock(&_lock);
NSMutableSet *infos = [_objectInfosMap objectForKey:object];
_FBKVOInfo *existingInfo = [infos member:info];
if (nil != existingInfo) {
NSLog(@"observation info already exists %@", existingInfo);
OSSpinLockUnlock(&_lock);
return;
}
且内部采用NSMapTable 作为容器存储被观察者和对应的观察者信息,类似于,但更加灵活和强大,支持添加指针、以及对象等,即允许指定加入容器中项的内存管理方式和类型行为,比如可以指定内存管理方式采用、和中的一种,还可以设定加入项的相等判断方式,比如指针或者方法。类似的容器还有和,分别对应于和。
中的构造方式如下:
NSPointerFunctionsOptions keyOptions = retainObserved ? NSPointerFunctionsStrongMemory|NSPointerFunctionsObjectPointerPersonality : NSPointerFunctionsWeakMemory|NSPointerFunctionsObjectPointerPersonality;
_objectInfosMap = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:NSPointerFunctionsStrongMemory|NSPointerFunctionsObjectPersonality capacity:0];
根据传入参数可以决定是否对被观察者维持一个强引用,对等的详细解释参考Pointer Function Options。表示对加入的项维持强引用,则相反。而通过指针判断加入的项是否相等,则通过加入对象的方法判断。其中为被观察者,为实例,也即观察者消息信息。
KVOController通过提供 _FBKVOSharedController 注册和转发消息,避免观察者直接使用 kvo,通过这个中间层达到了隔离的效果。并且提供一个跟观察者一一对应的 FBKVOController,过滤掉容易出错的注册和移除消息的请求,且 FBKVOController 生命周期跟观察者绑定,则观察者释放时,由 FBKVOController 生成的实例也被释放,从 _FBKVOSharedController 移除对应的观察者信息,避免发消息给已释放观察者导致的crash。
http://www.cnblogs.com/CoderPlace/p/4624229.html