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