iOS ReactiveCocoa框架的簡單使用

ReactiveCocoa框架的使用教程在網(wǎng)上有很多詳細(xì)的博客可參考,通過學(xué)習(xí),我自己也整理了一下,一來便于自己復(fù)習(xí),二來分享給大家。先粘貼些優(yōu)質(zhì)博文的鏈接,然后下面以實(shí)例的形式一步步講解。

優(yōu)質(zhì)技術(shù)博客鏈接

地址1:ReactiveCocoa入門教程——第一部分
地址2:ReactiveCocoa入門教程——第二部分
地址3:1個(gè)小時(shí)學(xué)會(huì)ReactiveCocoa基本使用

下面開始介紹ReactiveCocoa的使用

一、在項(xiàng)目中集成ReactiveCocoa框架

既然是第三方框架,那用CocoaPods集成是最方便的。
首先,創(chuàng)建一個(gè)工程
然后,在工程中創(chuàng)建Podfile文件,文件中的內(nèi)容如下:
platform :ios,'9.0'
use_frameworks!
target 'RWReactivePlayground' do
pod 'ReactiveCocoa', '~> 2.5'
end

注意1:

集成ReactiveCocoa框架和其他的不同之處是多了一個(gè)“use_frameworks!”,我在使用過程中發(fā)現(xiàn),2.5版本以上的更高的版本要加上“use_frameworks!”,否則會(huì)報(bào)錯(cuò),導(dǎo)致集成不了。而2.5版本之前的(包括2.5版本),就不需要加“use_frameworks!”,

注意2:

ReactiveCocoa現(xiàn)在的最高版本已經(jīng)到5.0了,問題是,如果用swift編程,那么集成最新版本的ReactiveCocoa框架沒有問題,但是如果使用OC編程的話,那最高只能集成2.5版本的RAC(RAC是ReactiveCocoa的簡稱),否則集成好了以后工程會(huì)報(bào)錯(cuò)。

簡單的說就是,如果你用swift編程,用Cocoapods集成時(shí),Podfile文件這么寫
platform :ios,'9.0'
use_frameworks!
target 'RWReactivePlayground' do
pod 'ReactiveCocoa', '~> 5.0'
end
如果你用的是oc編程,用Cocoapods集成時(shí),Podfile文件這么寫
platform :ios,'9.0'
target 'RWReactivePlayground' do
pod 'ReactiveCocoa', '~> 2.5'
end
最后,上面的工作都做好了,就可以集成RAC了,很快.


屏幕快照 2017-02-27 上午10.59.13.png
二、RAC的簡單使用----RACSignal

在要使用的RAC的控制器中導(dǎo)入RAC框架的頭文件

#import <ReactiveCocoa/ReactiveCocoa.h>

現(xiàn)在來熟悉下RACSignal的使用,從名字就可以看出,它是信號。在viewDidload中加入下面的代碼

//創(chuàng)建信號
    RACSignal * single = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"想");
        [subscriber sendNext:@"發(fā)送了信號"];//發(fā)送信號
        NSLog(@"你");
        [subscriber sendCompleted];//發(fā)送完成,訂閱自動(dòng)移除
        //RACDisposable 可用于手動(dòng)移除訂閱
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"豆腐");
        }];
    }];
    //訂閱信號
    NSLog(@"我");
    [single subscribeNext:^(id x) {
        NSLog(@"吃");
//        NSLog(@"信號的值:%@",x);
    }];

運(yùn)行,得到結(jié)果如下


RACSinale.png

這樣就可以清楚的看明白,信號的運(yùn)行流程,但是感覺好亂,下面分析一下:
1.createSignal方法 是創(chuàng)建信號,創(chuàng)建好的信號,沒有被訂閱前,只是冷信號,此時(shí)是不會(huì)走createSignal后面的block的。
程序往下,就走到“NSLog(@"我")”,

2.然后走到subscribeNext,這一步就是訂閱信號,訂閱號信號后,信號single就變成了熱信號,

3.既然變成熱信號,就開始走createSignal后面的block中的去,所以就打印出了“NSLog(@"想")”。

4.下面是sendNext,即發(fā)送信號,發(fā)送了信號,訂閱者就會(huì)收到信號,發(fā)送的內(nèi)容可以從訂閱信號subscribeNext后面的block中獲取到,程序就走到subscribeNext后面的block中,所以就打印了“NSLog(@"吃")”,

5.當(dāng)訂閱信號的subscribeNext后面的block走完以后,程序又回到,createSignal后面的block中,繼續(xù)未完成的代碼,所以就打印“NSLog(@"你")”,繼續(xù)往下就是[subscriber sendCompleted],這句代碼的意思是,發(fā)送完成了,訂閱自動(dòng)移除,沒有了訂閱者了,信號又變成了冷信號。

6.接下來就是return,返回一個(gè)RACDisposable對象,這個(gè)的作用就是,可以用來手動(dòng)移除訂閱。RACDisposable對象,創(chuàng)建完成,就走進(jìn)創(chuàng)建方法的block中,也就是打印NSLog(@"豆腐")

綜上,打印出來的結(jié)果就是“我想吃你豆腐”,它就是這樣出來的

這里再介紹下RACDisposable的使用,將代碼改一下

    //創(chuàng)建信號
    RACSignal * single = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"想");
        [subscriber sendNext:@"發(fā)送了一個(gè)信號"];//發(fā)送信號
        NSLog(@"你");
        //RACDisposable 手動(dòng)移除訂閱者
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"豆腐");
        }];
    }];
    //訂閱信號
    NSLog(@"我");
    RACDisposable * disposable = [single subscribeNext:^(id x) {
        NSLog(@"吃");
        NSLog(@"信號的值:%@",x);
    }];
    //手動(dòng)移除訂閱
    [disposable dispose];

打印結(jié)果如下



在稍微分析一下,兩份代碼不同之處是,刪去了自動(dòng)移除訂閱[subscriber sendCompleted],添加了手動(dòng)刪除訂閱[disposable dispose],手動(dòng)刪除訂閱,可以在你想要的地方,合適的時(shí)候進(jìn)行操作。不過手動(dòng)刪除用的少。那既然用得少,我們還是用自動(dòng)刪除吧,優(yōu)化下,見代碼

//創(chuàng)建信號
    RACSignal * single = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"想");
        [subscriber sendNext:@"發(fā)送了信號"];//發(fā)送信號
        NSLog(@"你");
        [subscriber sendCompleted];//發(fā)送完成,訂閱自動(dòng)移除
        //RACDisposable 手動(dòng)移除訂閱者
        return nil;
    }];
    //訂閱信號
    NSLog(@"我");
    [single subscribeNext:^(id x) {
        NSLog(@"吃");
        NSLog(@"信號的值:%@",x);
    }];

打印結(jié)果如下



好了,沒豆腐吃了!其實(shí)也不需要。返回nil就可以了

上面羅里吧嗦的說了那么多,就是為了理清里面的邏輯,沒有結(jié)合實(shí)際使用,其實(shí)聽起來還是很迷糊,下面就結(jié)合實(shí)際,來使用RAC

第二、RAC的常用方法

上面是使用RACSignal創(chuàng)建信號,其實(shí)文本框中文字改變也是信號,按鈕點(diǎn)擊也是信號,RAC為UITxtField和UIButton創(chuàng)建categary,并做好了封裝,直接就可以調(diào)用它們的信號,這里就圍繞著這兩個(gè)類,進(jìn)行ARC的使用講解
在工程中新建一個(gè)控制器,添加幾個(gè)控件,textField,textView,button,label,如下圖

訂閱textField信號

[self.textfield.rac_textSignal subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];

因?yàn)閠extField的信號肯定是NSString,類型的,所以可以寫成下面的樣子,也更方便使用些

[self.textfield.rac_textSignal subscribeNext:^(NSString* x) {
        NSLog(@"%@",x);
    }];

這樣,當(dāng)你在文本框輸入時(shí),控制臺就會(huì)打印出輸入的內(nèi)容,如下


可以看到,每次輸入都會(huì)獲取到信號。

filter---信號過濾器

如果我只需要將字符串長度超過3的,才打印,那可以使用過濾器filter,使用方法如下

[[self.textfield.rac_textSignal filter:^BOOL(NSString* value) {
        return value.length>3?YES:NO;
    }]subscribeNext:^(NSString* x) {
        NSLog(@"過濾后的到的信號:%@",x);
    }];

在文本框中輸入字符,打印結(jié)果如下



可以看到,只有當(dāng)字符串長度大于3的信號,才會(huì)被訂閱到

map--轉(zhuǎn)換器

map就是將一種信號轉(zhuǎn)換成你想要的另一種信號,這里把字符串信號,轉(zhuǎn)換成文字信號
如果想當(dāng)文本框中輸入的文字長度大于4的時(shí)候,改變文本框的背景色,一種方法是把過濾器的條件設(shè)置為4,然后在subscribeNext的block中直接給textField.backgroundColor賦值。不過RAC有轉(zhuǎn)換信號的方法---map,如下

[[[self.textfield.rac_textSignal filter:^BOOL(NSString* value) {
        return value.length>3?YES:NO;
    }]map:^id(NSString* value) {
        return value.length > 4?[UIColor redColor]:[UIColor whiteColor];
    }]subscribeNext:^(UIColor* value) {
        self.textfield.backgroundColor = value;
    }];

上面的代碼的意思是,當(dāng)輸入的字符串長度超過3,就將字符串信號轉(zhuǎn)換成顏色信號,然后訂閱該顏色信號,并將顏色賦值給textField的背景色。效果如下



這樣的話,當(dāng)字符串大于3,文本框的背景色變成了紅色
另外,RAC提供了一個(gè)宏"RAC(對象,屬性)"來簡化代碼并增強(qiáng)可讀性,如下

RAC(self.textfield ,backgroundColor) = [self.textfield.rac_textSignal map:^id(NSString* value) {
        return value.length > 4?[UIColor redColor]:[UIColor whiteColor];
    }];

RAC宏有兩個(gè)參數(shù),一個(gè)是需要設(shè)置的對象,一個(gè)是設(shè)置的屬性。這句代碼的意思是,當(dāng)文本框輸入的字符串長度大于4時(shí),改變文本框的背景色。這樣的話,看起來更清晰,而達(dá)到的效果是一樣的。

總結(jié)一下,到現(xiàn)在為止,學(xué)了過濾器:filter,轉(zhuǎn)換器:map,對象設(shè)置屬性的宏:RAC(要設(shè)置的對象,要設(shè)置的屬性)。可以想象,用這幾個(gè)方法可以很方便的實(shí)現(xiàn)一些功能,比喻說替代通知,監(jiān)聽事件等。

textField的使用是這樣,那textView的使用也是這樣的,因?yàn)樗麄兺耆愃?/p>

RAC(self.textView ,backgroundColor) = [self.textView.rac_textSignal map:^id(NSString* value) {
        return value.length > 4?[UIColor redColor]:[UIColor whiteColor];
    }];
combineLatest:reduce:

想象一下,如果當(dāng)textField和textView同時(shí)滿足某個(gè)條件時(shí),才能進(jìn)行某項(xiàng)操作的話,應(yīng)該如何寫呢?RAC為我們準(zhǔn)備了一個(gè)方法--combineLatest:reduce:信號合并
先看代碼

RACSignal * mergeTwoSignal = [RACSignal combineLatest:@[self.textfield.rac_textSignal,self.textView.rac_textSignal] reduce:^id(NSString * value1,NSString * value2){
        return [NSNumber numberWithBool:([value1 isEqualToString:@"11111"]&&[value2 isEqualToString:@"22222"])];
    }];
RAC(self.addButton,enabled) = [mergeTwoSignal map:^id(NSNumber* value) {
        return value;
    }];

上面的代碼的意思是,當(dāng)textField中的文字為"11111",同時(shí)textView中的文字為"22222"的時(shí)候,返回一個(gè)信號,信號的類型是NSNumber,然后通過轉(zhuǎn)換器map,將值返回,返回的值用于確定按鈕是否可用。
可能會(huì)疑問,map中返回的NSNumber類型的,而button的enabled屬性是BOOL類型,怎么可以這樣直接賦值,但是RAC它就是可以,就是做的這么好。
到這一步,就可以訂閱button的點(diǎn)擊信號了,看代碼就懂了

[[self.addButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
     subscribeNext:^(NSNumber * value) {
         //標(biāo)簽賦值
         self.displayLabel.text = @"1314";
     }];

運(yùn)行驗(yàn)證一下,結(jié)果如下



確實(shí)能達(dá)到要求。真好,再也不用給button 添加點(diǎn)擊事件了。

doNext

現(xiàn)在講一下附加操作doNext,它的作用是,在不改變信號的基礎(chǔ)上,進(jìn)行一些附加的操作,比喻說,我在訂閱到給label賦值前,改變label的背景色,當(dāng)然也可以是做別的操作。反正是附加的不會(huì)影響信號流的。使用見代碼

[[[self.addButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
     doNext:^(id x) {
         //改變label的背景色
         self.displayLabel.backgroundColor = [UIColor redColor];
     }]
     subscribeNext:^(NSNumber * value) {
         self.displayLabel.text = @"1314";
     }];

這樣就實(shí)現(xiàn)了,訂閱信號前,改變label的背景色

@weakify和@strongify

RAC的所有方法中,大部分是block,所以無法避免在使用過程中導(dǎo)致循環(huán)引用,
以前的解決辦法是這樣的

    __weak SecondViewController *bself = self;
    [[[self.addButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
        doNext:^(id x) {
            //先清掉label中的文字
            bself.displayLabel.textColor = [UIColor redColor];
        }]
       subscribeNext:^(NSNumber * value) {
           bself.displayLabel.text = @"1314";
       }];

如果每個(gè)block都寫的話,會(huì)很費(fèi)勁,因?yàn)閎lock太多了,還好RAC提供了兩個(gè)宏,@weakify和@strongify,

    @weakify(self);
    [[[self.addButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
      doNext:^(id x) {
          @strongify(self);
          self.displayLabel.textColor = [UIColor redColor];
      }]
     subscribeNext:^(NSNumber * value) {
         @strongify(self);
         self.displayLabel.text = @"1314";
     }];

@weakify宏讓你創(chuàng)建一個(gè)弱引用的影子對象(如果你需要多個(gè)弱引用,你可以傳入多個(gè)變量),@strongify讓你創(chuàng)建一個(gè)對之前傳入@weakify對象的強(qiáng)引用。這樣就解決了循環(huán)引用的問題

第三、RAC在網(wǎng)絡(luò)請求和圖片加載中的使用

先創(chuàng)建一個(gè)控制器,添加若干控件,textView,用來展示請求到的數(shù)據(jù),imageView,用來展示圖片,

使用系統(tǒng)的方法請求數(shù)據(jù)

在viewDidload中添加下面的代碼

    NSURL * url = [NSURL URLWithString:urlS];
    NSURLSession * session = [NSURLSession sharedSession];
    NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
    NSURLSessionTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSString * dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@",dataString);
        NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"%@",dic);
        [self performSelector:@selector(actionWithString:) onThread:[NSThread mainThread] withObject:dataString waitUntilDone:YES];
    }];
    [task resume];
//回到主線程給textView賦值
-(void)actionWithString:(id )value{
    self.textView.text = (NSString*)value;
}

結(jié)果如下


使用RAC請求網(wǎng)絡(luò)數(shù)據(jù)

把系統(tǒng)請求網(wǎng)絡(luò)數(shù)據(jù)的方法,封裝成信號流

//rac網(wǎng)絡(luò)請求
-(RACSignal *)racNetworkRequest{
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSURL * url = [NSURL URLWithString:urlS];
        NSURLSession * session = [NSURLSession sharedSession];
        NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
        NSURLSessionTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSString * dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//            NSLog(@"%@",dataString);
//            NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
//            NSLog(@"%@",dic);
            if (error ==nil) {//返回成功
                [subscriber sendNext:dataString];//發(fā)送信號
                [subscriber sendCompleted];//結(jié)束發(fā)送
            } else {
                [subscriber sendError:error];//發(fā)送錯(cuò)誤
            }
        }];
        [task resume];
        return nil;
    }];
}

現(xiàn)在就來調(diào)用一下看看,在viewDidLoad中添加下面的代碼,
self.requestDataButton是一個(gè)按鈕,使用方法是點(diǎn)擊按鈕的時(shí)候加載數(shù)據(jù)

    [[[self.requestDataButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
    map:^id(id value) {
        return [self racNetworkRequest];
    }]
    subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];

訂閱信號后,得到的數(shù)據(jù)如下



發(fā)現(xiàn),得到的不是想要的數(shù)據(jù),而是一個(gè)信號對象,其實(shí)從racNetworkRequest這個(gè)方法中就可以看出,返回就是一個(gè)RACSignal對象,如果能獲取到RACSignal對象里面的信號流就對了,怎么辦呢,RAC提供了這樣的方法 flattenMap

flattenMap---獲取信號中的信號

把上面的代碼寫成這樣,就可以獲取到數(shù)據(jù)了

    [[[self.requestDataButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
      flattenMap:^id(id value) {
          return [self racNetworkRequest];
      }]
     subscribeNext:^(id x) {
         NSLog(@"%@",x);
     } error:^(NSError *error) {
         NSLog(@"%@",error);
     }];

這樣就會(huì)發(fā)現(xiàn)訂閱到的信號,是你想要的數(shù)據(jù)了。

then---等待上一個(gè)信號的完成,然后訂閱自己的信號
    [[[self racNetworkRequest]
    then:^RACSignal *{
        return self.textField.rac_textSignal;
    }]
    subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }error:^(NSError *error) {
        NSLog(@"error");
    }];

then方法會(huì)等待前面的信號中completed事件的發(fā)送完成,然后再訂閱由then block返回的信號。這樣就高效地把控制權(quán)從一個(gè)signal傳遞給下一個(gè)。如此就實(shí)現(xiàn)了:當(dāng)請求數(shù)據(jù)完成,就可以監(jiān)控到textField中的文字輸入了

回到主線程---deliverOn

因?yàn)樾盘柕牧鬓D(zhuǎn)及操作都是在block中完成的,也就是說大部分操作都是在子線程中執(zhí)行的操作,但是有個(gè)時(shí)候需要回到主線程完成一些事情,比如,請求到數(shù)據(jù)后,要刷新UI,這就必須回到主線程,RAC提供了這樣的方法deliverOn。用法見下面的代碼

    @weakify(self)
    [[[[[self racNetworkRequest]
        then:^RACSignal *{
            @strongify(self);
            return self.textField.rac_textSignal;
        }]
       filter:^BOOL(NSString* value) {
           return value.length > 3?YES:NO;
       }]
    deliverOn:[RACScheduler mainThreadScheduler]]//回到主線程
    subscribeNext:^(NSString * value) {
         @strongify(self);
         self.textView.text =value;
         NSLog(@"%@",value);
        NSLog(@"當(dāng)前線程%@",[NSThread currentThread]);
    } error:^(NSError *error) {
         NSLog(@"%@",error);
     }];

這樣的話,實(shí)現(xiàn)的效果就是,在textField中輸入文字而且當(dāng)文字大于3的時(shí)候,會(huì)在textView中顯示出來,而且可以看到訂閱信號的block中打印出來的線程是主線程,如下:



悲催的是,如果沒有加deliverOn:好像也是在主線程。我也不知道什么原因,不知道有沒有用,姑且就認(rèn)為deliverOn有用,可能在開啟很多線程的時(shí)候會(huì)有用吧
不過我可以在subscribeNext的block中加入回到主線程的方法,也能達(dá)到目的,如下

    subscribeNext:^(NSString * value) {
         @strongify(self);
         self.textView.text =value;
         NSLog(@"%@",value);
        [self performSelectorOnMainThread:@selector(doSomething) withObject:nil waitUntilDone:YES];
        NSLog(@"當(dāng)前線程%@",[NSThread currentThread]);
    } error:^(NSError *error) {
         NSLog(@"%@",error);
     }];
信號節(jié)流---throttle

用文本框textField作比喻,當(dāng)我在里面輸入字符時(shí),subscribeNext的block會(huì)不停的走,每輸入一個(gè)字符,就會(huì)走一遍。如果我想在輸入過程中不需要每改變一個(gè)字符就走一遍,而是等輸入完成或停止的時(shí)候再走block里面的代碼,那就可以用throttle,先看效果

    [[[self.textField.rac_textSignal
       filter:^BOOL(NSString* value) {
           return value.length > 3?YES:NO;
       }]
      throttle:1]
     subscribeNext:^(NSString * value) {
         @strongify(self);
         self.textView.text =value;
     } error:^(NSError *error) {
         NSLog(@"%@",error);
     }];

這樣得到的效果是,當(dāng)輸入字符串長度大于3,而且該字符串的值在1s內(nèi)沒有改變,就把textField中的值,賦值給textView。所以簡單的說throttle的作用:如果前面信號在設(shè)定的時(shí)間內(nèi)沒有變化時(shí),throttle就會(huì)把信號傳到下面的事件中去。

使用系統(tǒng)的方法加載圖片

系統(tǒng)的方法,我就不說了 看代碼

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSURL * url = [NSURL URLWithString:imageUrlString];
        UIImage * image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
        if (image!=nil) {
            dispatch_async(dispatch_get_main_queue(), ^{
                self.imageView.image = image;
            });
        }
    });

這樣就可以完成圖片的加載,看下面的效果


RAC加載圖片

創(chuàng)建一個(gè)加載圖片的方法,方法返回的是RACSignle信號對象,

-(RACSignal*)racRequestImage{
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSURL * url = [NSURL URLWithString:imageUrlString];
        UIImage * image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
        self.imageView.image = image;
        [subscriber sendNext:image];
        [subscriber sendCompleted];
        return nil;
    }];
}

下面就來調(diào)用這個(gè)方法。實(shí)現(xiàn)的效果是,點(diǎn)擊按鈕(self.requestImageDataButton),即開始加載圖片,在viewDidLoad中添加下面的代碼

    @weakify(self);
    [[[self.requestImageDataButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
       flattenMap:^RACStream *(id value) {
           return [self racRequestImage];
       }]
    deliverOn:[RACScheduler mainThreadScheduler]]
    subscribeNext:^(UIImage * image) {
        @strongify(self);
         self.imageView.image = image;
     }];

運(yùn)行一下,發(fā)現(xiàn),圖片加載正常。從代碼量來看,GCD可能方便一點(diǎn),但是,如果是多個(gè)事件湊到一起影響圖片加載的時(shí)候,RAC或許是不錯(cuò)的選擇。

到這一步,就把ReactiveCocoa的初步使用講完了。
總結(jié)一下總共學(xué)習(xí)哪些方法

filter---信號過濾器
map--轉(zhuǎn)換器
combineLatest:reduce:--信號合并
doNext--附加操作
@weakify和@strongify--避免循環(huán)
flattenMap---獲取信號中的信號
then---等待上一個(gè)信號的完成,然后訂閱自己的信號
回到主線程---deliverOn
信號節(jié)流---throttle
第四、demo下載

GitHub下載地址

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

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