FBKVOController 源码阅读笔记
FBKVOContoller是Facebook推出的KVO的库,目的在于简化KVO的代码编写,它提供了干净的block回调,避免了散落到各处的处理逻辑。
结构分析
FBKVOController主要由以下三个部分组成:
- FBKVOInfo
- FBKVOSharedController
- FBKVOControlller
FBKVOInfo
FBKVOInfo
用来作为KVO中的Context,它的定义如下:
1 | @implementation _FBKVOInfo { @public __weak FBKVOController *_controller; NSString *_keyPath; NSKeyValueObservingOptions _options; SEL _action; void *_context; FBKVONotificationBlock _block; _FBKVOInfoState _state; } |
_FBKVOInfoState
的定义如下:
1 | typedef NS_ENUM(uint8_t, _FBKVOInfoState) { _FBKVOInfoStateInitial = 0, // whether the observer registration in Foundation has completed _FBKVOInfoStateObserving, // whether `unobserve` was called before observer registration in Foundation has completed // this could happen when `NSKeyValueObservingOptionInitial` is one of the NSKeyValueObservingOptions _FBKVOInfoStateNotObserving, }; |
以上的定义基本可以后名字推断,就不再赘述。
FBKVOSharedController
FBKVOSharedController是一个单例,所有的观察信息以FBKVOInfo的形式交由其处理,FBKVOSharedController内部实现了KVO机制,当FBKVOInfo中的keypath对应的属性发生改变,那么对应的回调就会被执行。
具体的代码如下:
1 | - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable 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]; } } } } } |
FBKVOSharedController还定义了以下三个方法,用于添加删除FBKVOInfo到其维护的一个NSHashTabe<_fbkvoinfo *="">中。
代码如下:
1 | - (void)observe:(id)object info:(nullable _FBKVOInfo *)info - (void)unobserve:(id)object info:(nullable _FBKVOInfo *)info - (void)unobserve:(id)object infos:(nullable NSSet<_FBKVOInfo *> *)infos |
FBKVOController
FBKVOController内部维护了一个NSMapTable
除此之外,FBKVOController只是简单的地调用FBKVOSharedController提供的方法来添加/删除观察对象。