ReactiveCocoa-上手其實很簡單(二)

fighting.jpg

上篇寫的ReactiveCocoa-上手其實很簡單(一),相信大家已經對RAC有了 感悟,對其簡單的運用應該也是沒什么問題的,如果有些模糊我們可以回顧下上一篇文章講解,俗話說:溫故而知新、書讀百遍,其義自見嘛。
今天我們來進一步了解RAC的核心類及RAC的進階使用。

關于RACSubject

RACSubject:信號提供者,非常特殊,自己可以充當信號,又能發送信號。
場景:一般在傳值、回調的時候、替代delegate的時候使用。
下面來看個例子:當前控制器點擊按鈕,push到另一個控制器界面,另一個控制器點擊按鈕,返回控制器的第一個頁面和接收到第二個界面的消息。
OneViewController

- (void)viewDidLoad {  
    [super viewDidLoad];  
  
    /* 
     // RACSubject使用步驟 
     // 1.創建信號 [RACSubject subject],創建信號時沒有block。 
     // 2.訂閱信號 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock 
     // 3.發送信號 sendNext:(id)value 
      
     // RACSubject:底層實現和RACSignal不一樣。 
     // 1.調用subscribeNext訂閱信號,只是把訂閱者保存起來,并且訂閱者的nextBlock已經賦值了。 
     // 2.調用sendNext發送信號,遍歷剛剛保存的所有訂閱者,一個一個調用訂閱者的nextBlock。 
      
     */  
    self.button.frame = CGRectMake(100, 100, 80, 30);  
    [self.view addSubview:self.button];  
}  

#pragma mark---lazy loading  
- (UIButton *)button {  
    if (!_button) {  
        _button = [[UIButton alloc] init];  
        [_button setBackgroundColor:[UIColor redColor]];  
        [_button setTitle:@"Go To" forState:UIControlStateNormal];  
//使用rac_signalForControlEvents,處理button點擊事件
        [[_button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {  
           TwoViewController *twoVC = [[TwoViewController alloc] init];  
//1.創建信號 [RACSubject subject]
           twoVC.subject = [RACSubject subject];  
//2.調用sendNext發送信號
           [twoVC.subject subscribeNext:^(id x) {  // 這里的x便是sendNext發送過來的信號  
                NSLog(@"%@", x);  
                [self.button setTitle:x forState:UIControlStateNormal];  
            }];  
              
            [self.navigationController pushViewController:twoVC animated:YES];  
              
        }];  
    }  
    return _button;  
}  

TwoViewController

@property (nonatomic,strong) RACSubject *subject;

- (void)viewDidLoad {  
    [super viewDidLoad];  
   self.button.frame = CGRectMake(50, 100, 50, 30);  
    self.view.backgroundColor = [UIColor purpleColor];  
    [self.view addSubview:self.button];  
}  

#pragma mark---lazy loading  
- (UIButton *)button {  
    if (!_button) {  
        _button = [[UIButton alloc] init];  
        [_button setBackgroundColor:[UIColor grayColor]];  
        [_button setTitle:@"Two Go" forState:UIControlStateNormal];  
        [[_button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {  
//3.發送信號,傳遞的值,替代delegate
             [self.subject sendNext:@"zm"];  
             [self.navigationController popViewControllerAnimated:YES];  
        }];  
    }  
    return _button;  
}  

RACSubject和RACReplaySubject的區別:
RACSubject必須要先訂閱信號之后才能發送信號,而RACReplaySubject可以先發送信號后訂閱,重復提供信號類。
使用場景一:如果一個信號每被訂閱一次,就需要把之前的值重復發送一遍,使用重復提供信號類。

使用場景二:可以設置capacity數量來限制緩存的value的數量,即只緩充最新的幾個值。

關于RACCommand

RACCommand:RAC中用于處理事件的類,可以把事件如何處理,事件中的數據如何傳遞,包裝到這個類中,他可以很方便的監控事件的執行過程。
場景:監聽按鈕點擊,網絡請求
注意事項:
1.signalBlock不能返回nil,必須返回一個信號或者[RACSignal empty]
2.RACCommand中信號如果數據傳遞完,必須調用[subscriber sendCompleted],代表執行完畢,否則永遠處于執行中。
3.特別注意RACCommand需要被強引用,否則接收不到RACCommand中的信號,RACCommand中的信號是延遲發送的。
獲取RACCommand返回的信號源數據執行方法:
1.執行信號源executionSignals,這個是signal of signals(信號的信號),意思是信號發出的數據是信號,不是普通的類型。
2.訂閱executionSignals就能拿到RACCommand中返回的信號,然后訂閱signalBlock返回的信號,就能獲取發出的值。
3.監聽當前命令是否正在執行executing
具體實現例子:

- (void)test1 {  
    // RACCommand: 處理事件  
     //1.創建
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {  
        //block調用,execute執行命令的時候就會調用  
         // input 為執行命令傳進來的參數  
        // 不能返回空的信號  這里的返回值不允許為nil  
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {  
            [subscriber sendNext:@"執行命令產生的數據"];  
            return nil;  
        }];  
    }];  
  
    // 訂閱命令內部的信號  
    // ** 方式一:直接訂閱執行命令返回的信號  
    //2.執行命令
    RACSignal *signal =[command execute:@1]; // 這里其實用到的是replaySubject 可以先發送命令再訂閱  
    // 在這里就可以訂閱信號了  
    [signal subscribeNext:^(id x) {  
        NSLog(@"%@",x);  
    }];  

//**方法二:
// 訂閱signal of signals(信號的信號)  
// 注意:這里必須是先訂閱才能發送命令  
 // executionSignals:信號源,信號中信號,signalofsignals:信號,發送數據就是信號  
    [command.executionSignals subscribeNext:^(RACSignal *x) {  
        [x subscribeNext:^(id x) {  
            NSLog(@"%@", x);  
        }];  
//        NSLog(@"%@", x);  
    }];  

    // 2.執行命令  
    [command execute:@2];  

// **方式三  
    // switchToLatest獲取最新發送的信號,只能用于信號中信號。  
    [command.executionSignals.switchToLatest subscribeNext:^(id x) {  
        NSLog(@"%@", x);  
    }];  
    // 2.執行命令  
    [command execute:@3]; 
}

/* 
 RACCommand 通常用來表示某個Action的執行,比如點擊Button。它有幾個比較重要的屬性:executionSignals / errors / executing。 
  
 1、executionSignals是signal of signals,如果直接subscribe的話會得到一個signal,而不是我們想要的value,所以一般會配合switchToLatest。 
 2、errors。跟正常的signal不一樣,RACCommand的錯誤不是通過sendError來實現的,而是通過errors屬性傳遞出來的。 
 3、executing表示該command當前是否正在執行。 
 */  

// 監聽事件有沒有完成  
- (void)test2 {  
    //注意:當前命令內部發送數據完成,一定要主動發送完成  
    // 1.創建命令  
    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {  
        // block調用:執行命令的時候就會調用  
        // 這里的返回值不允許為nil  
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {  
            // 發送數據  
            [subscriber sendNext:@"執行命令產生的數據"];  
              
            // *** 發送完成 **  
            [subscriber sendCompleted];  
            return nil;  
        }];  
    }];  
    // 監聽事件有沒有完成  
    [command.executing subscribeNext:^(id x) {  
        if ([x boolValue] == YES) { // 正在執行  
            NSLog(@"當前正在執行%@", x);  
        }else {  
            // 執行完成/沒有執行  
            NSLog(@"執行完成/沒有執行");  
        }  
    }];  
      
    // 2.執行命令  
    [command execute:@1];  
      
}  
關于RACMulticastConnection

RACMulticastConnection:用于當一個信號,被多次訂閱時,為了保證創建信號時,避免多次調用創建信號中的block,造成副作用,可以使用這個類處理。
注意事項:RACMulticastConnection通過RACSignal的-publish或者-muticast:方法創建.
使用場景:解決多次調用問題--假設在一個信號中發送請求,每次訂閱一次都會發送請求,這樣就會導致多次請求。
使用步驟:
1.創建信號 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
2.創建連接 RACMulticastConnection *connect = [signal publish];
3.訂閱信號,注意:訂閱的不在是之前的信號,而是連接的信號。 [connect.signal subscribeNext:nextBlock]
4.連接 [connect connect]
具體實現例子:

- (void)test {
 // 使用RACMulticastConnection,無論有多少個訂閱者,無論訂閱多少次,只發送一個。  
    // 1.發送請求,用一個信號內包裝,不管有多少個訂閱者,只想發一次請求  
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {  
        // 發送請求  
        NSLog(@"發送請求啦");  
        // 發送信號  
        [subscriber sendNext:@"data"];  
        return nil;  
    }];  
    //2. 創建連接類  
    RACMulticastConnection *connection = [signal publish];  
    [connection.signal subscribeNext:^(id x) {  
        NSLog(@"%@", x);  
    }];  
    [connection.signal subscribeNext:^(id x) {  
         NSLog(@"%@", x);  
    }];  
    [connection.signal subscribeNext:^(id x) {  
         NSLog(@"%@", x);  
    }];  
    //3. 連接。只有連接了才會把信號源變為熱信號  
    [connection connect];  
}  

今天就寫到這里,這篇主要寫了下一些常用的使用類及常用的使用場景,下篇準備寫下操作符的使用。大家有什么疑惑的可以留言。

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

推薦閱讀更多精彩內容