ReactiveCocoa 更優(yōu)雅的編程(信號探秘)

ReactiveCocoa(簡稱為RAC),是由Github開源的一個應用于iOS和OS開發(fā)的框架.

RAC 的核心思想:創(chuàng)建信號 - 訂閱信號 - 發(fā)送信號 我們按照這個步驟來 一步一步的實現(xiàn) 并且探尋RAC 里面是怎么的一個原理

信號寫法

  • 第一種寫法
 NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
 RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
     NSLog(@"創(chuàng)建信號");
     //發(fā)送信號
     [subscriber sendNext:array];  
     return nil;
 }];
 [signal subscribeNext:^(id  _Nullable x) {
      NSLog(@"訂閱信號%@",x);
 }];
  • 第二種寫法 上面的方式縮寫
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
      NSLog(@"創(chuàng)建信號");
      //發(fā)送信號
      [subscriber sendNext:array];
      return nil;
 }]subscribeNext:^(id  _Nullable x) {
       NSLog(@"訂閱信號%@",x);
 }];
  • 為了便于理解 我們先按照順序分步驟寫 探尋每個方法里面的秘密

創(chuàng)建信號 內(nèi)部的秘密

  • 如我們下面這行代碼,就是創(chuàng)建信號。RACSignal 的類方法createSignal,帶block回調(diào),里面有一個參數(shù)RACSubscriber。整個方法返回一個RACSignal對象。 創(chuàng)因為沒有訂閱者。稱為冷信號
RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
       NSLog(@"創(chuàng)建信號");
       return nil;
}];

下面我們進入 createSignal方法看看里面怎么實現(xiàn)的

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    return [RACDynamicSignal createSignal:didSubscribe];
}
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];
}

看到createSignal方法里面 創(chuàng)建了一個 RACDynamicSignal對象,我們可以把它理解為一個動態(tài)信號。同時對一個didSubscribe這個block 進行了一個保存

訂閱信號 內(nèi)部的秘密

  • 訂閱信號 RACSignal 對象 調(diào)用一個方法 subscribeNext,方法 返回一個RACDisposable對象(可以先不看這個) ,寫了subscribeNext 方法的信號,因為有了訂閱者稱為熱信號。
 [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"訂閱信號%@",x);
 }];

下面我們進入 subscribeNext 方法看看 里面有什么

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}
//進入subscriberWithNext方法
+ (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;
}

看到 subscribeNext里 調(diào)用subscriberWithNext里面 創(chuàng)建了一個 RACSubscriber 對象(這是一個有意思的現(xiàn)象 ,在上面 創(chuàng)建信號的里面 我們見到了 創(chuàng)建方法里 保存了一個didSubscribe block 也是RACSubscriber,它的實質(zhì)就是創(chuàng)建信號的block)。同時 對 _next _error _completed 三個block 進行了保存 并執(zhí)行了RACSubscriber

發(fā)送信號 內(nèi)部的秘密

  • 就一句簡單 sendNext: 如果沒有這句,我是訂閱者是沒法獲取數(shù)據(jù)的
    // 發(fā)送信號 
    [subscriber sendNext:@“我是內(nèi)容”];

下面我們進入 sendNext 方法看看 里面有什么
sendNext 在 多個類都有此方法

DF47B9BC-1A2A-4C63-A140-85F7263CC0FB.png

點擊 RACSubject sendNext:
里面是醬紫的

- (void)sendNext:(id)value {
    [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
        [subscriber sendNext:value];
    }];
}

調(diào)用 [RACSubject sendNext] 時
RACSubject就會遍歷一遍自己的subcribers數(shù)組,并調(diào)用各數(shù)組元素(subscriber)準備好的Block
繼續(xù)點擊RACSubscriber sendNext

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

        nextBlock(value);
    }
}

又見到了 熟悉的面孔 上面 訂閱信號保存的一個_next block ,
把 之前在訂閱信號保存的_next block 進行賦值并執(zhí)行。

整理一下

看了一會 這么多方法,這些貌似有聯(lián)系,但是又模模糊糊的。我們和代碼結(jié)合起來看

 NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
一. //創(chuàng)建信號
1.創(chuàng)建了一個 RACDynamicSignal
2.保存了一個 didSubscribe block
 RACSignal *signal=[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
     NSLog(@"創(chuàng)建信號");
     三.//發(fā)送信號
    1.執(zhí)行訂閱信號保存的_next block 。
     [subscriber sendNext:array];  
     return nil;
 }];
二.//訂閱信號
1.保存了_next _error _completed 三個block 
2.執(zhí)行創(chuàng)建信號時所保存的didSubscribe block
 [signal subscribeNext:^(id  _Nullable x) {
      NSLog(@"訂閱信號%@",x);
 }];

看了大約能明白 都是block 在互相關聯(lián)
我們在用圖了解一些整個信號的運行原理

E8278B36-AA87-43B1-99A1-AF1E58B11218.png

創(chuàng)建信號 - 訂閱信號 - 發(fā)送信號 就是這樣實現(xiàn)的
不得不佩服ReactiveCocoa 的作者們,給我們在開啟了一座新的大門。它的編程思想真的值得我們?nèi)W習一下。

結(jié)尾:水平有限,代碼也很爛,一直在努力學習中,大家多多包涵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容