文档章节

FBKVOController实现

s
 summer_liu
发布于 2014/12/09 18:28
字数 841
阅读 914
收藏 0

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];
}


© 著作权归作者所有

s
粉丝 0
博文 1
码字总数 841
作品 0
广州
私信 提问
[iOS]KVOController踩坑记

KVO 作为 iOS 中一种强大并且有效的机制,为我们检测对象属性的变化提供了帮助; 但系统提供的KVO接口实在太麻烦,所以开发过程中,我们使用了facebook 开源的KVOController。 今天和大家分享...

ChenHuaHeng
2017/12/15
0
0
iOS kvo 结合 FBKVOController 的使用

iOS kvo 结合 FBKVOController 的使用 iOS kvo 结合 FBKVOController 的使用 一:FBKVOControlloer是FaceBook开源的一个 在 iOS,maxOS上使用 kvo的 开源库; 提供了block和@selector(SEL) ...

法斗斗
2016/12/27
37
0
KVOController详解

KVO在MVC的项目布局中是一种特别有用的技术。KVOController建立在Cocoa经受时间考验的KVO实现上。它提供简单、现代的API,并且是线程安全的。优点如下: 通知是通过block、action或者NSKeyVa...

西瓜冰soso
2018/05/26
0
0
iOS开发中的实用功能

嵌套UIScrollview的滑动冲突解决方案 虽然苹果建议我们不要嵌套 UIScrollview ,但是这话到底是对开发者说的,架不住设计师就是要这么画设计图。我遇到的场景类似这样,顶部有一个优先展示的...

掘金官方
2017/12/18
0
0
MJRefresh源码剖析与学习

建议查看原文:https://www.jianshu.com/p/23c876f8ae39(不定时更新) 源码剖析学习系列:(不断更新) 1、FBKVOController源码剖析与学习 2、MJRefresh源码剖析与学习 3、YYImage源码剖析与...

Dwyane_Coding
2018/09/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

nginx学习之模块

1、 stub_status模块: 用于展示nginx处理连接时的状态。 配置语法如下: Syntax:stub_status;Default:默认没有配置Context:server、location 可以编辑default.conf,加上如下配置: ...

码农实战
48分钟前
4
0
MySQL,必须掌握的6个知识点

目录 一、索引B+ Tree 原理 MySQL 索引 索引优化 索引的优点 索引的使用条件 二、查询性能优化使用 Explain 进行分析 优化数据访问 重构查询方式 三、存储引擎InnoDB MyISAM 比较 四、数据类...

李红欧巴
51分钟前
4
0
堆”和“栈

C++作为一款C语言的升级版本,具有非常强大的功能。它不但能够支持各种程序设计风格,而且还具有C语言的所有功能。我们在这里为大家介绍的是其中一个比较重要的内容,C++内存区域的基本介绍。...

SibylY
今天
4
0
总结:Https

一、介绍 简单理解,https即在http协议的基础上,增加了SSL协议,保障数据传输的安全性。 它由以前的http—–>tcp,改为http——>SSL—–>tcp;https采用了共享密钥加密+公开密钥加密的方式 ...

浮躁的码农
今天
6
0
数据库表与表之间的一对一、一对多、多对多关系

表1 foreign key 表2 多对一:表 1 的多条记录对应表 2 的一条记录 利用foreign key的原理我们可以制作两张表的多对多,一对一关系 多对多: 表1的多条记录可以对应表2的一条记录 表2的多条记...

Garphy
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部