我們都知道 ReactiveObjC 的編程思想主要是 響應(yīng)式編程 的概念 , 而 RACObserve 是使用了原生的 KVO 與 響應(yīng)式編程 相結(jié)合的產(chǎn)物。
現(xiàn)在開始對(duì) RACObserve 的監(jiān)聽流程進(jìn)行分析,現(xiàn)在VC聲明一下屬性,如下:
//ViewController.m
@property (nonatomic, strong) Dog *dog;
@property (nonatomic, copy) NSString *name;
我們使用的 RACObserve 是一個(gè)宏定義,里面?zhèn)魅氲膮?shù)為:
RACObserve(TARGET, KEYPATH)
[RACObserve(self, name) subscribeNext:^(id _Nullable x) {
// 這里會(huì)得到被監(jiān)聽值的最終結(jié)果
}];
那么這個(gè)宏定義 RACObserve 實(shí)際又是一個(gè)什么東西呢?我們看一下源碼:
#define _RACObserve(TARGET, KEYPATH) \
({ \
// 把傳入的被觀察對(duì)象進(jìn)行了 weak 引用
__weak id target_ = (TARGET); \
[target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH)
observer:self]; \
})
#if __clang__ && (__clang_major__ >= 8)
#define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)
#else
#define RACObserve(TARGET, KEYPATH) \
({ \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wreceiver-is-weak\"") \
_RACObserve(TARGET, KEYPATH) \
_Pragma("clang diagnostic pop") \
})
#endif
RACObserve 實(shí)質(zhì)是繼續(xù)調(diào)用了 _RACObserve(TARGET, KEYPATH)
#define _RACObserve(TARGET, KEYPATH) \
({ \
__weak id target_ = (TARGET); \
[target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]; \
})
// 是 NSObject+RACPropertySubscribing.h 里的兩個(gè)方法
[target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self];
NSObject+RACPropertySubscribing
看第一個(gè)方法即可 OS_OBJECT_HAVE_OBJC_SUPPORT
// NSObject+RACPropertySubscribing.h
#if OS_OBJECT_HAVE_OBJC_SUPPORT
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath
observer:(__weak NSObject *)observer;
#else
// Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :(
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath
observer:(NSObject *)observer;
#endif
這里實(shí)際是封裝了一個(gè) RACSignal 對(duì)象,外部調(diào)用的 RACObserve(TARGET, KEYPATH) 是返回一個(gè)(RACSignal *)對(duì)象
// NSObject+RACPropertySubscribing.m
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath
observer:(__weak NSObject *)observer {
/*
這里實(shí)際是封裝了一個(gè) RACSignal 對(duì)象,
RACObserve() 的宏返回的是 (RACSignal *)
*/
return [[[self rac_valuesAndChangesForKeyPath:keyPath options:NSKeyValueObservingOptionInitial
observer:observer]
map:^(RACTuple *value) {
return value[0];
}]
setNameWithFormat:@"RACObserve(%@, %@)", RACDescription(self), keyPath];
}
- (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
observer:(__weak NSObject *)weakObserver {
NSObject *strongObserver = weakObserver;
keyPath = [keyPath copy];
// 產(chǎn)生了一個(gè)遞歸鎖
NSRecursiveLock *objectLock = [[NSRecursiveLock alloc] init];
objectLock.name = @"org.reactivecocoa.ReactiveObjC.NSObjectRACPropertySubscribing";
__weak NSObject *weakSelf = self;
// 創(chuàng)建了一個(gè) 銷毀信號(hào)量, 假如:vc 調(diào)用了 RACObserve(TARGET, KEYPATH),但vc被銷毀了,這個(gè)信號(hào)就會(huì)發(fā)出一個(gè)銷毀信號(hào)
RACSignal *deallocSignal = [[RACSignal
zip:@[
self.rac_willDeallocSignal,
strongObserver.rac_willDeallocSignal ?: [RACSignal never]
]]
doCompleted:^{
[objectLock lock];
@onExit {
[objectLock unlock];
};
}];
// takeUntil:deallocSignal 判斷當(dāng)前觀察者是否銷毀了,如果銷毀了就不會(huì)對(duì)進(jìn)入以下監(jiān)聽工作
return [[[RACSignal
createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
[objectLock lock];
@onExit {
[objectLock unlock];
};
__strong NSObject *observer __attribute__((objc_precise_lifetime)) = weakObserver;
__strong NSObject *self __attribute__((objc_precise_lifetime)) = weakSelf;
if (self == nil) {
[subscriber sendCompleted];
return nil;
}
//以下方法進(jìn)行傳值監(jiān)聽, 看這里?。?! 看這里?。。?看這里?。。? return [self rac_observeKeyPath:keyPath options:options
observer:observer
block:^(id value, NSDictionary *change,
BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
/*
將得到的新值通過block回調(diào)到這里,
并使用 sendNext 發(fā)送出去外部訂閱的 subscribeNext
*/
[subscriber sendNext:RACTuplePack(value, change)];
}];
}]
takeUntil:deallocSignal]
setNameWithFormat:@"%@ -rac_valueAndChangesForKeyPath: %@ options: %lu observer: %@",
RACDescription(self), keyPath, (unsigned long)options, RACDescription(strongObserver)];
}
// 點(diǎn)擊此方法,跳轉(zhuǎn)到 NSObject+RACKVOWrappe.m
[self rac_observeKeyPath:keyPath options:options observer:observer
block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
[subscriber sendNext:RACTuplePack(value, change)];
}];
NSObject+RACKVOWrapper
// NSObject+RACKVOWrapper.m
- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
observer:(__weak NSObject *)weakObserver
block:(void (^)(id, NSDictionary *, BOOL, BOOL))block
此方法上半部分做了一大堆關(guān)于 Disposable 銷毀信號(hào)準(zhǔn)備工作 ,下半部分做了銷毀操作等等,這里就不作過多的分析了;
/*
獲取keyPath 的路由,
比如 VC 有一個(gè) Dog 類并監(jiān)聽 dog.name, RACObserve(vc,dog.name)
*/
NSArray *keyPathComponents = keyPath.rac_keyPathComponents;
// 獲取 被監(jiān)聽對(duì)象的 "屬性列表"
objc_property_t property = class_getProperty(object_getClass(self), keyPathHead.UTF8String);
我們重點(diǎn)看 傳值監(jiān)聽 過程,以下代碼:
/*
KVO: 面向?qū)ο?, 誰調(diào)用誰被監(jiān)聽
此處把所有的相關(guān)參數(shù)傳入,如:觀察者,被觀察對(duì)象,keyPath 等,
用 RACKVOTrampoline 進(jìn)行了封裝,此類是監(jiān)聽工作開始的起點(diǎn),block的回調(diào)得到監(jiān)聽的最終結(jié)果
*/
RACKVOTrampoline *trampoline =
[[RACKVOTrampoline alloc] initWithTarget:self
observer:strongObserver
keyPath:keyPathHead
options:trampolineOptions
block:^(id trampolineTarget, id trampolineObserver, NSDictionary *change) {
/*
RACKVOTrampoline.m 里的響應(yīng)監(jiān)聽方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
會(huì)把新值 Block 到這里來
*/
if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) {
[firstComponentDisposable() dispose];
if ((options & NSKeyValueObservingOptionPrior) != 0) {
block([trampolineTarget valueForKeyPath:keyPath], change, NO, keyPathHasOneComponent);
}
return;
}
if (value == nil) {
block(nil, change, NO, keyPathHasOneComponent);
return;
}
// 銷毀操作
RACDisposable *oldFirstComponentDisposable = [firstComponentSerialDisposable swapInDisposable:[RACCompoundDisposable compoundDisposable]];
[oldFirstComponentDisposable dispose];
addDeallocObserverToPropertyValue(value);
if (keyPathHasOneComponent) {
block(value, change, NO, keyPathHasOneComponent);
return;
}
addObserverToValue(value);
// block 返回到 (NSObject + RACPropertySubscribing.m) 的信號(hào)量定義 block里, 并 sendNext
block([value valueForKeyPath:keyPathTail], change, NO, keyPathHasOneComponent);
}];
點(diǎn)擊以上 RACKVOTrampoline 的實(shí)例方法 進(jìn)入到 RACKVOTrampoline.m
RACKVOTrampoline
這里的重點(diǎn)在于:RACKVOProxy.sharedProxy 這個(gè)單例做了一個(gè)神秘操作,比如 被監(jiān)聽對(duì)象 有可能需要 觀察多個(gè)對(duì)象或其他屬性(上述代碼中,被監(jiān)聽對(duì)象是 VC ,所以被監(jiān)聽的對(duì)象會(huì)有:name,dog 等等)。
可理解為:每一個(gè)被監(jiān)聽的對(duì)象封裝成一個(gè) RACKVOTrampoline 對(duì)象,
并把這些被已封裝的 trampoline 對(duì)象全部添加到 sharedProxy 單例里面統(tǒng)一監(jiān)聽。
//RACKVOTrampoline.m
- (instancetype)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
NSCParameterAssert(keyPath != nil);
NSCParameterAssert(block != nil);
NSObject *strongTarget = target;
if (strongTarget == nil) return nil;
self = [super init];
_keyPath = [keyPath copy];
_block = [block copy];
_weakTarget = target;
_unsafeTarget = strongTarget;
_observer = observer;
/*
移交代理 --- 觀察對(duì)象
被監(jiān)聽對(duì)象 有可能需要觀察多個(gè)對(duì)象或其他屬性(如:VC的屬性有 name,dog等等),
可理解為:每一個(gè)被監(jiān)聽的對(duì)象封裝成一個(gè) RACKVOTrampoline 對(duì)象,
并把這些被已封裝的 trampoline 對(duì)象全部添加到 sharedProxy 單例里面統(tǒng)一監(jiān)聽,如下一行代碼:
*/
[RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
/*
然而 strongTarget(VC) 只需要觀察 RACKVOProxy.sharedProxy ,
并把相應(yīng)的 keyPath 傳給此單例即可 ,統(tǒng)一用 shareProxy 處理,如下一行代碼:
*/
[strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
// 添加銷毀者
[strongTarget.rac_deallocDisposable addDisposable:self];
[self.observer.rac_deallocDisposable addDisposable:self];
return self;
}
- (void)dealloc {
// 進(jìn)行移除監(jiān)聽、信號(hào)銷毀
[self dispose];
}
#pragma mark Observation
- (void)dispose {
NSObject *target;
NSObject *observer;
@synchronized (self) {
_block = nil;
target = self.unsafeTarget;
observer = self.observer;
_unsafeTarget = nil;
_observer = nil;
}
// 銷毀操作
[target.rac_deallocDisposable removeDisposable:self];
[observer.rac_deallocDisposable removeDisposable:self];
// 移除監(jiān)聽
[target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
[RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context != (__bridge void *)self) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
RACKVOBlock block;
id observer;
id target;
// 面向?qū)ο蟮幕麨榱?,線性安全
@synchronized (self) {
block = self.block;
observer = self.observer;
target = self.weakTarget;
}
if (block == nil || target == nil) return;
/*
數(shù)值發(fā)生改變,然后調(diào)用 block 返回到 NSObject + RACKVOWrapper.m 這個(gè)類里面
即: RACKVOTrampoline *trampoline 實(shí)例化的 block 里面
*/
block(target, observer, change);
}
@end
RACKVOProxy
我們?cè)倏匆幌?RACKVOProxy.sharedProxy 這個(gè)單例里面有做了些什么操作:
RACKVOProxy.m 聲明了兩個(gè)屬性,分別是: NSMapTable *trampolines用于保存 RACKVOTrampoline對(duì)象;dispatch_queue_t queue用于確保線性安全
// RACKVOProxy.m
@interface RACKVOProxy()
@property (strong, nonatomic, readonly) NSMapTable *trampolines;
@property (strong, nonatomic, readonly) dispatch_queue_t queue;
@end
@implementation RACKVOProxy
+ (instancetype)sharedProxy {
static RACKVOProxy *proxy;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
proxy = [[self alloc] init];
});
return proxy;
}
- (instancetype)init {
self = [super init];
// 串行,線性安全:確保每次數(shù)值改變是有序的
_queue = dispatch_queue_create("org.reactivecocoa.ReactiveObjC.RACKVOProxy", DISPATCH_QUEUE_SERIAL);
_trampolines = [NSMapTable strongToWeakObjectsMapTable];
return self;
}
- (void)addObserver:(__weak NSObject *)observer forContext:(void *)context {
NSValue *valueContext = [NSValue valueWithPointer:context];
// 把被觀察的對(duì)象 放到 trampolines(表) 里去
dispatch_sync(self.queue, ^{
[self.trampolines setObject:observer forKey:valueContext];
});
}
- (void)removeObserver:(NSObject *)observer forContext:(void *)context {
NSValue *valueContext = [NSValue valueWithPointer:context];
dispatch_sync(self.queue, ^{
[self.trampolines removeObjectForKey:valueContext];
});
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSValue *valueContext = [NSValue valueWithPointer:context];
__block NSObject *trueObserver;
dispatch_sync(self.queue, ^{
// 取出被改變值的對(duì)象
trueObserver = [self.trampolines objectForKey:valueContext];
});
if (trueObserver != nil) {
/*
使用對(duì)應(yīng)的 RACKVOTrampoline 對(duì)象返回出去給 “RACKVOTrampoline” 這個(gè)類中的
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
*/
[trueObserver observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end
發(fā)生回調(diào)時(shí)響應(yīng)以下數(shù)據(jù),分別是修改前、修改后的數(shù)據(jù)(為了不產(chǎn)生誤會(huì),說明一下以下兩張圖可以忽略掉其他控件的屬性,我只抽出了 dog、name 來說明)


然后會(huì)通過
[trueObserver observeValueForKeyPath:keyPath ofObject:object change:change context:context];
發(fā)送出去 RACKVOTrampoline.m 的
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
以下附上一張流程圖:
image.png
以上內(nèi)容純粹個(gè)人見解,僅用于分享交流;如有描述不當(dāng)之處,歡迎指出。
