about 1 year ago

關於 ReactiveCocoa 的介紹,網路上已經有許多資源可以參考,
想要特別提醒的是,目前在 ReactiveCocoa 的官方 GitHub 中,
有分 ReactiveCocoa, ReactiveSwift, ReactiveObjC 等 repo,
原因是從 ReactiveCocoa 3.0 開始便只支援 Swift 語法。
所以如果想使用單純 Objective-C 的版本,目前最穩定的版本為 2.5。

以下的範例都是使用 2.5 版本的 ReactiveObjC。

Signal

Signal 是 ReactiveCocoa 的主要基本概念,
創建 Signal 以及訂閱 Signal ,而資料的流向會以 Signal 發送至訂閱對象。

Create Signal & Subscribe Signal

以下為創建 Signal 以及訂閱 Signal 的範例,
其中 createSignal 可以回傳一個 RACDisposable 的 block,
這個 block 會在此 Signal 結束或取消後執行。

sendNext 會將 value 傳送至訂閱對象的 subscribeNext block 中。

RACSignal *skSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"123"];
    [subscriber sendCompleted];
    return [RACDisposable disposableWithBlock:^{
                
    }];
}];

[skSignal subscribeNext:^(id x) {

}];

RAC()

RAC 可將 object 的 property 訂閱 Signal,透過 Signal 最後回傳的 value 來取代此 property。

RACSignal *skSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"123"];
    [subscriber sendCompleted];
    return nil;
}];
NSLog(@"%@",self.value);
RAC(self,value) = skSignal;
NSLog(@"%@",self.value);
RACObserve()

RACObserve 會產生一個 Signal,此 Signal 可直接綁定某個 Object 的 property。

RACObserve(self, self.value);

配合 RAC(),就可以讓某個 object 的 property 去訂閱另外一個 object 的 value。

RAC(object1, object1.value) = RACObserve(object2, object2.value);
Signal Flow

可以串起多個 Signal 成為一個可處理複雜資料的程序。

  • then

當 Signal 處理完成後,可以使用 then 在後面接上另外一個 Signal。
有幾點要特別說明。

  1. sendNext 與 sendCompleted 會由最後一個處理的 Signal 送給訂閱對象。
  2. 前一個 Signal 一定要執行 sendCompleted 才會交由下一個 Signal 執行。
  3. 若前一個 Singal 執行 sendError,便會停下程序,並傳送 error 給訂閱對象。
    RACSignal s = [[RACSignal createSignal:^RACDisposable (id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"1"];
        [subscriber sendCompleted];
        return nil;
    }] then:^RACSignal {
    return [RACSignal createSignal:^RACDisposable (id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"2"];
        [subscriber sendCompleted];
        return nil;
    }];
    }];
    
  • doNext

doNext 的 block 會在 Signal sendNext 前先被執行。
且 sendNext 的 value 也會被帶到 doNext 的 block 中。

RACSignal *s = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"2"];
    [subscriber sendCompleted];
    return nil;
}] doNext:^(id x) {
    NSLog(@"123");
}];
  • map

map 的功能是在 Signal sendNext 時先將 value 帶到 map block 中,
最後回傳一個新的 value。

RACSignal *s = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"2"];
    [subscriber sendCompleted];
    return nil;
}] map:^id(id value) {
    return @"4";
}];
  • flattenMap

flattenMap 基本流程與 then 相同,差別在於可直接將前一個 Signal 的結果傳遞給下一個 Signal 來處理。

RACSignal *s = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"2"];
    [subscriber sendCompleted];
    return nil;
}] flattenMap:^RACStream *(id value) {
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"2"];
        [subscriber sendCompleted];
        return nil;
    }];
}];
  • initially

初始化的 block 可以在執行 Signal 先被執行。

RACSignal *s = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"2"];
    [subscriber sendCompleted];
    return nil;
}] initially:^{
    NSLog(@"123");
}];
← iOS Objective-C 動態置換實作 建立 Proxy Server ( 使用 AWS EC2 與 Squid ) →