FBKVOController实现

FBKVOController主要包括3个类,_FBKVOInfo,FBKVOController,_FBKVOSharedController。对外暴露的是FBKVOController。安全

一、FBKVOInfo:是个结构类,model。包含一些变量。多线程

@implementation _FBKVOInfo
{
@public
  __weak FBKVOController *_controller;
  NSString *_keyPath;
  NSKeyValueObservingOptions _options;
  SEL _action;
  void *_context;
  FBKVONotificationBlock _block;
}

action,block都是处理函数,当监听到value变化时调用的。在_FBKVOSharedController中会被调用函数

二、_FBKVOSharedController:主要用来添加监听,而且监听到事件以后的处理。性能

@implementation _FBKVOSharedController
{
  NSHashTable *_infos;
  OSSpinLock _lock;
}

_infos存储被监听的对象。spa

_lock是自旋锁,在多线程同时访问公共对象时保证线程安全。这里是在对_infos进行操做的时候使用。它快速,安全,性能消耗小。线程

三、FBKVOController:对外提供接口的类。它包含的变量也比较简单code

@implementation FBKVOController
{
  NSMapTable *_objectInfosMap;
  OSSpinLock _lock;
}

NSMapTable *_objectInfosMap;(存储键值对,object对应其要监听的keypath)orm

OSSpinLock _lock;(同上,自旋锁)server




NSMapTable:NSDictionary的进化,能够设置对象的强弱引用。对象

NSHashTable:NSSet的进化,一样也能够设置对象的强弱引用。




FBKVOController的使用

一、initWithObserver生成FBKVOController对象。

二、- (void)observe:(id)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(FBKVONotificationBlock)block;

使用block或者SEL均可以。

以上2步就是调用的主流程。



具体实现

主要讲调用第二步以后内部是怎么实现的。

一、首先initWithObserver生成了FBKVOInfo,初始化一些信息。而后调用_observe函数,将info当作参数传入。使用锁,保证线程安全。

- (void)_observe:(id)object info:(_FBKVOInfo *)info
{
  // lock
  OSSpinLockLock(&_lock);
  
  NSMutableSet *infos = [_objectInfosMap objectForKey:object];
  
  // check for info existence
  _FBKVOInfo *existingInfo = [infos member:info];
  if (nil != existingInfo) {
    NSLog(@"observation info already exists %@", existingInfo);
    
    // unlock and return
    OSSpinLockUnlock(&_lock);
    return;
  }
  
  // lazilly create set of infos
  if (nil == infos) {
    infos = [NSMutableSet set];
    [_objectInfosMap setObject:infos forKey:object];
  }
  
  // add info and oberve
  [infos addObject:info];
  
  // unlock prior to callout
  OSSpinLockUnlock(&_lock);
  
  [[_FBKVOSharedController sharedController] observe:object info:info];
}

mapTable以obj做为key,NSMutableSet(对象类型为FBKVOInfo)做为value。

首先检查存不存在info。存在则直接返回,不存在就添加到set中,而后调用FBKVOSharedController的observe函数。


该函数主要就是addobserver。

- (void)observe:(id)object info:(_FBKVOInfo *)info
{
  if (nil == info) {
    return;
  }
  
  // register info
  OSSpinLockLock(&_lock);
  [_infos addObject:info];
  OSSpinLockUnlock(&_lock);
  
  // add observer
  [object addObserver:self forKeyPath:info->_keyPath options:info->_options context:(void *)info];
}


当有监听事件发生时,监听函数会被调用。

此时的处理,就是调用对应controller传入的回调函数,block或者是action。这样就完成了事件的监听处理。

#pragma clang使用来去掉编译器警告。没有实现selector的警告。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
  NSAssert(context, @"missing context keyPath:%@ object:%@ change:%@", keyPath, object, change);
  
  _FBKVOInfo *info;
  
  {
    // lookup context in registered infos, taking out a strong reference only if it exists
    OSSpinLockLock(&_lock);
    info = [_infos member:(__bridge id)context];
    OSSpinLockUnlock(&_lock);
  }
  
  if (nil != info) {
    
    // take strong reference to controller
    FBKVOController *controller = info->_controller;
    if (nil != controller) {
      
      // take strong reference to observer
      id observer = controller.observer;
      if (nil != observer) {
        
        // dispatch custom block or action, fall back to default action
        if (info->_block) {
          info->_block(observer, object, change);
        } else if (info->_action) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
          [observer performSelector:info->_action withObject:change withObject:object];
#pragma clang diagnostic pop
        } else {
          [observer observeValueForKeyPath:keyPath ofObject:object change:change context:info->_context];
        }
      }
    }
  }
}


还有对应的unobserve,将object从mapTable中移除掉。

- (void)_unobserve:(id)object info:(_FBKVOInfo *)info
{
  // lock
  OSSpinLockLock(&_lock);
  
  // get observation infos
  NSMutableSet *infos = [_objectInfosMap objectForKey:object];
  
  // lookup registered info instance
  _FBKVOInfo *registeredInfo = [infos member:info];
  
  if (nil != registeredInfo) {
    [infos removeObject:registeredInfo];
    
    // remove no longer used infos
    if (0 == infos.count) {
      [_objectInfosMap removeObjectForKey:object];
    }
  }
  
  // unlock
  OSSpinLockUnlock(&_lock);
  
  // unobserve
  [[_FBKVOSharedController sharedController] unobserve:object info:registeredInfo];
}


一样调用FBKVOSharedController的unobserve。最后仍是调用NSObject对象的removeObserver

- (void)unobserve:(id)object info:(_FBKVOInfo *)info
{
  if (nil == info) {
    return;
  }
  
  // unregister info
  OSSpinLockLock(&_lock);
  [_infos removeObject:info];
  OSSpinLockUnlock(&_lock);
  
  // remove observer
  [object removeObserver:self forKeyPath:info->_keyPath context:(void *)info];
}
相关文章
相关标签/搜索