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];
}
相關文章
相關標籤/搜索