RAC 之 RACSignal 使用與源碼分析

RACSignal 使用

   // 1 創(chuàng)建信號
    @weakify(self)
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        @strongify(self)
        self.subsrcribe = subscriber;

        // 3 發(fā)送信號
        [subscriber sendNext:@"hahah"];

        return [RACDisposable disposableWithBlock:^{
            NSLog(@"銷毀了");
        }];
    }];

    // 2 訂閱信號
    [signal subscribeNext:^(id  _Nullable x) {
        // 第 3 步 發(fā)送信號后, 此處 block 會被回調(diào)
        NSLog(@"subscribeNext:%@",x);
    }];

根據(jù)上述代碼流程,RACSignal 的使用分別有 3 步

  • 創(chuàng)建:實(shí)例一個(gè) RACSignal對象,并實(shí)現(xiàn)一個(gè)能夠獲取 subscriber 訂閱者的 block
  • 訂閱:使用RACSignal對象進(jìn)行訂閱,用于獲取發(fā)送信號后的回調(diào)結(jié)果
  • 發(fā)送信號:使用subscriber 訂閱者在特定位置發(fā)送信號(發(fā)送結(jié)果),訂閱信號的 block 獲取結(jié)果

一、RACSignal 的創(chuàng)建

以下我們開始分析一下 RACSignal類型的對象是怎么來的

    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        return [RACDisposable disposableWithBlock:^{
            
        }];
    }];

上述RACSignal 的創(chuàng)建 方法,

//  RACSignal.h
+ (RACSignal<ValueType> *)createSignal:
(RACDisposable * _Nullable (^)(id<RACSubscriber> subscriber))didSubscribe
//  RACSignal.m
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
     //RACDynamicSignal 繼承于 RACSignal
    return [RACDynamicSignal createSignal:didSubscribe];
}

因?yàn)榉祷氐氖? RACSignal類型,卻使用了

return [RACDynamicSignal createSignal:didSubscribe];

由此可得 RACDynamicSignal 這個(gè)子類做了一系列的實(shí)例化和包裝處理,如下:

//RACDynamicSignal.m

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
        //  setNameWithFormat: 進(jìn)行了一些列的底層打印日志操作,
       //   最后還是返回了一個(gè) RACSignal 的對象
    return [signal setNameWithFormat:@"+createSignal:"];
}

二、RACSignal 訂閱信號

    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"subscribeNext:%@",x);
    }];

上述方法是在 RACSignal (Subscription)類別里的一個(gè)方法:

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    // 創(chuàng)建 subscribe 對象 并保存 Next、Error、Completed 三個(gè)Block
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    // 傳入 subscribe 并創(chuàng)建 disposable
    return [self subscribe:o];
}

RACSubscriber的對象主要保存了 Next、Error、Completed 3個(gè)Block,再往里面跟一層如下:

// RACSubscriber.m
+ (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;
}

然后回到 上面的類別: RACSignal (Subscription)

  return [self subscribe:o];

上述方法雖然是在本類別里調(diào)用

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCAssert(NO, @"This method must be overridden by subclasses");
    return nil;
}

但卻被子類 RACDynamicSignal 重寫了

// RACDynamicSignal.m
#pragma mark Managing Subscribers
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);

    // 傳入 subscribe 并創(chuàng)建 disposable,
    // 復(fù)合銷毀者
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    
    /**
     *  subscriber --- RACSubscriber
     *  signal     --- self 
     *  disposable
     */

    //  新的(RACPassthroughSubscriber*)subscriber 擁有:disposable、signal、subscribe 三者合成
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

    // signal 有執(zhí)行 didsubscribe Block 往下走
    if (self.didSubscribe != NULL) {
        
        //  這里需要注意!!?。? 如果開啟了異步操作,RACScheduler.subscriptionScheduler 的類型是 “RACTargetQueueScheduler” 并在子線程執(zhí)行 【RACTargetQueueScheduler schedule:】
        
        RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
            // 這一步 self.didSubscribe(subscriber) 進(jìn)行block 回調(diào)出去
            RACDisposable *innerDisposable = self.didSubscribe(subscriber);
            // 添加銷毀
            [disposable addDisposable:innerDisposable];
        }];

        [disposable addDisposable:schedulingDisposable];
    }
    
    return disposable;
}

上述代碼我們主要看訂閱者subscriber 的回調(diào)流程:

// 只要外部執(zhí)行了
[RACSignal  createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
  // 這里得到 subscriber 的底層回調(diào)
}

 當(dāng)?shù)讓邮褂?self.didSubscribe(subscribe) 就會回調(diào)出去上面的代碼塊里

小結(jié)一下整個(gè)訂閱過程主要做了的就是:
signal 訂閱了 subscribeNext:^(id _Nullable x) 的 block,并內(nèi)部配置了 subscribe,即:

    subscriber->_next = [next copy];
    subscriber->_error = [error copy];
    subscriber->_completed = [completed copy];

此時(shí) subscriber擁有了下面 signal的block 實(shí)現(xiàn)

// 三種訂閱原理都是一樣
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"subscribeNext:%@",x);
     }];

    [signal subscribeError:^(NSError * _Nullable error) {
        NSLog(@"subscribeError");
    }];

    [signal subscribeCompleted:^{
        NSLog(@"subscribeCompleted");
    }];

下一步subscriber 就可以根據(jù)不同場景發(fā)送信號進(jìn)行 block 回調(diào)了

三、 RACSignal 發(fā)送信號

使用subscriber發(fā)送信號:

        [subscriber sendNext:@"hahah"];
    
        [subscriber sendError:nil];

        [subscriber sendCompleted];
// RACSubscriber.m
#pragma mark RACSubscriber

- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;
        nextBlock(value);
    }
}

- (void)sendError:(NSError *)e {
    @synchronized (self) {
        void (^errorBlock)(NSError *) = [self.error copy];
        // 在回調(diào) block 之前 ,執(zhí)行了銷毀方法
        [self.disposable dispose];

        if (errorBlock == nil) return;
        errorBlock(e);
    }
}

- (void)sendCompleted {
    @synchronized (self) {
        void (^completedBlock)(void) = [self.completed copy];
        // 在回調(diào) block 之前 ,執(zhí)行了銷毀方法
        [self.disposable dispose];

        if (completedBlock == nil) return;
        completedBlock();
    }
}

上面 subscriber 根據(jù)不同方法分別調(diào)用了 nextBlock(value),errorBlock(e),completedBlock() 使得第二步 signal的訂閱信號得到了回調(diào)結(jié)果;

值得注意的是:

- (void)sendError:(NSError *)e
- (void)sendCompleted;

這兩個(gè)方法的實(shí)現(xiàn)里,分別都調(diào)用了

[self.disposable dispose];

這部操作把 subscriber進(jìn)行了銷毀, 之后的subscriber如果再調(diào)用 sendNext, sendError , sendCompleted 或其他發(fā)送信號的方法,都已經(jīng)失效了。

關(guān)于 RACSignal,RACSubscriber 就暫時(shí)介紹到這里,上述涉及到RACDisposable,RACScheduler 沒有作出過多的解釋,后續(xù)抽時(shí)間會繼續(xù)寫下去。

以上內(nèi)容純粹個(gè)人見解,僅用于分享交流;如有描述不當(dāng)之處,歡迎指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容