FBKVOController实现原理(简单描述)

您所在的位置:网站首页 世上是不是有神仙:生命与疾病的真相呢 FBKVOController实现原理(简单描述)

FBKVOController实现原理(简单描述)

2022-06-10 08:27| 来源: 网络整理| 查看: 265

在看这篇文章之前,建议自己写一个小的FBKVOController Example,如果懒得写可以在Github上clone我写的一个非常简单的example。这样能建立一个大体的了解。

对代码中的细节部分没有做介绍,例如锁机制,Set,Map这些,只要知道作用即可,不影响对核心代码的理解。

代码结构: 1.FBKVOController 对外公开的类,对外提供了初始化,数种监听的方法。 2._FBKVOInfo 内部类,用来记录监听所需的参数信息。 3._FBKVOSharedController 内部类,真正实现kvo的类,通过FBKVOController的外部方法调用。 内部实现 1.在ViewController中初始化,调用。 ViewController.m @property (nonatomic,strong) FBKVOController * kvoController; @property (nonatomic,strong) DataModel * model; ..... self.kvoController = [FBKVOController controllerWithObserver:self];//初始化FBKVOController self.model = [[dataView alloc] init];//被监听的model [self.kvoController observe:_model keyPath:@"colorString" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial block:^(ViewController * observer, id object, NSDictionary *change) { //some code in block //.... }];

KVOController有两种监听方式:一种是block,另一种是用action(或者selector)的方式,上面是block方式。

上面代码实现的是监听_model中的colorString属性,当该数值初始化(NSKeyValueObservingOptionInitial)或者重新赋值(NSKeyValueObservingOptionNew)时,执行block中的代码。

2 .FBKVOController提供的外部方法 - (void)observe:(id)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(FBKVONotificationBlock)block { NSAssert(0 != keyPath.length && NULL != block, @"missing required parameters observe:%@ keyPath:%@ block:%p", object, keyPath, block); if (nil == object || 0 == keyPath.length || NULL == block) { return; } // create info _FBKVOInfo *info = [[_FBKVOInfo alloc] initWithController:self keyPath:keyPath options:options block:block]; // observe object with info [self _observe:object info:info]; }

FBKVOController的监听方法首先会检查参数的合法性,如果参数为NULL,则直接return,否则将接受的参数通过// create info 这段代码存储到类info中,然后调用方法: - (void)_observe:(id)object info:(_FBKVOInfo *)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]; }

该方法首先检查一下之前是否有重复监听的属性,如果有的话,直接返回,否则就调用_FBKVOSharedController中的监听方法,之前说过,_FBKVOSharedController是真正实现监听的内部类。

3 . _FBKVOSharedController内部类

FBKVO实现代码使用了很多C,C++的语法。至此开始真正进入observe的具体实现。

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

该方法前面都是对参数的记录,最后一段代码是关键:

[object addObserver:self forKeyPath:info->_keyPath options:info->_options context:(void *)info];

这段代码中,object是之前被监听的_model类,self是 _FBKVOSharedController,在从头理一遍代码,我们的初衷是要监听 _model类中的属性,在这里变成监听 _FBKVOSharedController中的属性。而且是调用的系统方法:

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context; //API1

_FBKVOSharedController内部调用上面系统提供的方法,然后重写了另一个系统方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context //API2

通过调用API1,对属性进行监听,如果属性出现变化的时候,系统会去调用API2,重写API2,可以控制KVO的具体实现,不论是增加block还是action都可以在API2中进行。

下面是API2的具体实现:

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

方法会检测,是否要执行block,如果block参数不为空则执行:info->_block(observer, object, change); 如果有action,则用performSelector:执行action,否则调用系统自带的监听方法。

如果有任何问题欢迎再下面留言,或者扫描二维码 wechat



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3