簡介
ReactiveObjc將原有的各種設(shè)計模式讥蟆,包括代理、Target/Action停撞、block、通知中心以及觀察者模式各種『輸入』,都抽象成了數(shù)據(jù)流或者信號(也可以理解為狀態(tài)流)讓單一的組件能夠?qū)ψ约旱捻憫?yīng)動作進(jìn)行控制戈毒,簡化了視圖控制器的負(fù)擔(dān)艰猬。ReactiveObjc整個框架主要是圍繞Signal來運轉(zhuǎn)。
我們先來看一段代碼
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"釋放");
}];
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
這段代碼的打印
2021-04-12 15:15:31.988297+0800 ZLXStudyDemo[64724:7390883] 1
2021-04-12 15:15:31.988485+0800 ZLXStudyDemo[64724:7390883] 2
2021-04-12 15:15:31.988587+0800 ZLXStudyDemo[64724:7390883] 3
2021-04-12 15:15:34.694916+0800 ZLXStudyDemo[64724:7390883] 釋放
這段代碼包含ReactiveObjc的信號完成使用邏輯埋市。
我們先大致分析下:通過RACSignal的createSignal:創(chuàng)建一個signal->signal通過subscribeNext:訂閱一個信號-> RACSubscriber通過sendNext來觸發(fā)訂閱的信號冠桃。
下面我們從以下四方來解析上述過程的原理:
- 信號的創(chuàng)建
- 信號的訂閱
- 訂閱的響應(yīng)
- 訂閱的回收
信號的創(chuàng)建
RACSignal是ReactiveObjc框架信號處理的核心。信號的創(chuàng)建我們主要來看下這個類道宅。
先看下創(chuàng)建相關(guān)的代碼:
// step1
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"釋放");
}];
}];
// step2
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
//step3
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
信號的創(chuàng)建是不是非常簡單腊满。
- RACSignal調(diào)用create內(nèi)部再調(diào)用RACDynamicSignal的create
-
RACDynamicSignal將傳入Subscribeblock綁定到RACDynamicSignal的didSubscribe屬性上。
image.png
所以整個信號的訂閱我們可以理解為:綁定信號關(guān)聯(lián)的block到RACDynamicSignal的didSubscribe屬性上培己。
這個關(guān)聯(lián)的block什么時候觸發(fā)呢? 怎么觸發(fā)的呢胚泌? 接下來我們來看下信號的訂閱省咨。
信號的訂閱
ReactiveObjc訂閱的相關(guān)邏輯我們主要看RACSubscriber
訂閱相關(guān)的代碼:
// step1
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
// step2
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
NSCParameterAssert(nextBlock != NULL);
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
return [self subscribe:o];
}
//step3
+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
RACSubscriber *subscriber = [[self alloc] init];
subscriber->_next = [next copy];
subscriber->_error = [error copy];
subscriber->_completed = [completed copy];
return subscriber;
}
//step4
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
if (self.didSubscribe != NULL) {
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
RACDisposable *innerDisposable = self.didSubscribe(subscriber);
[disposable addDisposable:innerDisposable];
}];
[disposable addDisposable:schedulingDisposable];
}
return disposable;
}
我們來分析下訂閱的過程:
- RACSignal調(diào)用訂閱API,傳入訂閱的block
- 創(chuàng)建RACSubscriber,并綁定上一步的block
- RACSignal調(diào)用subscribe玷室,傳入上一步創(chuàng)建的RACSubscriber零蓉,
- 調(diào)用之前RACSignal信號創(chuàng)建時候綁定的didSubscribe,并傳入上一步傳入的RACSubscriber
讓我們在看看看剛開始的代碼穷缤,現(xiàn)在知道[subscriber sendNext:@"1"];這個subscriber是什么時候創(chuàng)建的了嗎敌蜂?上面的步驟2
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 這個subscriber什么時候創(chuàng)建的呢?
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"釋放");
}];
}];
訂閱的響應(yīng)
//step1 調(diào)用sendNext
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"1"];
[subscriber sendNext:@"2"];
[subscriber sendNext:@"3"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"釋放");
}];
}];
//step2 調(diào)用nextBlock
- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
// 響應(yīng)block
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
這個流程是不是很簡單津肛。給你個問題 nextblock哪里來的章喉?
訂閱的取消
RACDisposable 是訂閱回收的核心。主要思想是用來處理異步的操作身坐。
每一個異步操作關(guān)聯(lián)一個RACDisposable秸脱,當(dāng)執(zhí)行操作的時候,去check RACDisposable的狀態(tài)部蛇。
我們來看下之前的訂閱代碼
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
//step1 創(chuàng)建一個容器disposable摊唇,可以同時處理多個disposable
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
//消息轉(zhuǎn)發(fā)。主要作用是check disposable狀態(tài)
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
if (self.didSubscribe != NULL) {
//step2
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
RACDisposable *innerDisposable = self.didSubscribe(subscriber);
//step3
[disposable addDisposable:innerDisposable];
}];
//step4
[disposable addDisposable:schedulingDisposable];
}
return disposable;
}
我們來看下代碼吧涯鲁,每次執(zhí)行操作的時候都去check下disposed巷查。
- (RACDisposable *)schedule:(void (^)(void))block {
NSCParameterAssert(block != NULL);
RACDisposable *disposable = [[RACDisposable alloc] init];
dispatch_async(self.queue, ^{
if (disposable.disposed) return;
[self performAsCurrentScheduler:block];
});
return disposable;
}
// RACSubscriber 釋放調(diào)用掛載的RACDisposable的block
- (void)dealloc {
[self.disposable dispose];
}