码迷,mamicode.com
首页 > 其他好文 > 详细

FBKVOController实现

时间:2014-12-10 12:51:22      阅读:552      评论:0      收藏:0      [点我收藏+]

标签:style   io   ar   color   os   使用   sp   for   strong   

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

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

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

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

2、_FBKVOSharedController:主要用来添加监听,并且监听到事件之后的处理。

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

_infos存储被监听的对象。

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

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

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

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

OSSpinLock _lock;(同上,自旋锁)




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

NSHashTable:NSSet的进化,同样也可以设置对象的强弱引用。




FBKVOController的使用

1、initWithObserver生成FBKVOController对象。

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

使用block或者SEL都可以。

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



具体实现

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

1、首先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];
}


FBKVOController实现

标签:style   io   ar   color   os   使用   sp   for   strong   

原文地址:http://my.oschina.net/u/861778/blog/354285

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!