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的使用,從名字就可以看出讼昆,它是信號(hào)托享。在viewDidload中加入下面的代碼

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

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


RACSinale.png

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

2.然后走到subscribeNext,這一步就是訂閱信號(hào)卦方,訂閱號(hào)信號(hào)后羊瘩,信號(hào)single就變成了熱信號(hào),

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

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

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

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

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

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

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

打印結(jié)果如下



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

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

第二赴叹、RAC的常用方法

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

訂閱textField信號(hào)

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

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

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

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


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

filter---信號(hào)過濾器

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

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

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



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

map--轉(zhuǎn)換器

map就是將一種信號(hào)轉(zhuǎn)換成你想要的另一種信號(hào)犀暑,這里把字符串信號(hào),轉(zhuǎn)換成文字信號(hào)
如果想當(dāng)文本框中輸入的文字長度大于4的時(shí)候烁兰,改變文本框的背景色耐亏,一種方法是把過濾器的條件設(shè)置為4,然后在subscribeNext的block中直接給textField.backgroundColor賦值沪斟。不過RAC有轉(zhuǎn)換信號(hào)的方法---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,就將字符串信號(hào)轉(zhuǎn)換成顏色信號(hào)主之,然后訂閱該顏色信號(hào)择吊,并將顏色賦值給textField的背景色。效果如下



這樣的話槽奕,當(dāng)字符串大于3几睛,文本框的背景色變成了紅色
另外,RAC提供了一個(gè)宏"RAC(對(duì)象,屬性)"來簡化代碼并增強(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è)置的對(duì)象,一個(gè)是設(shè)置的屬性琼讽。這句代碼的意思是必峰,當(dāng)文本框輸入的字符串長度大于4時(shí),改變文本框的背景色钻蹬。這樣的話,看起來更清晰凭需,而達(dá)到的效果是一樣的问欠。

總結(jié)一下肝匆,到現(xiàn)在為止,學(xué)了過濾器:filter,轉(zhuǎn)換器:map,對(duì)象設(shè)置屬性的宏:RAC(要設(shè)置的對(duì)象顺献,要設(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:信號(hào)合并
先看代碼

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è)信號(hào),信號(hào)的類型是NSNumber,然后通過轉(zhuǎn)換器map优俘,將值返回京办,返回的值用于確定按鈕是否可用。
可能會(huì)疑問帆焕,map中返回的NSNumber類型的臂港,而button的enabled屬性是BOOL類型,怎么可以這樣直接賦值视搏,但是RAC它就是可以审孽,就是做的這么好。
到這一步浑娜,就可以訂閱button的點(diǎn)擊信號(hào)了佑力,看代碼就懂了

[[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漓滔,它的作用是编饺,在不改變信號(hào)的基礎(chǔ)上,進(jìn)行一些附加的操作响驴,比喻說透且,我在訂閱到給label賦值前,改變label的背景色,當(dāng)然也可以是做別的操作秽誊。反正是附加的不會(huì)影響信號(hào)流的鲸沮。使用見代碼

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

這樣就實(shí)現(xiàn)了,訂閱信號(hào)前锅论,改變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è)弱引用的影子對(duì)象(如果你需要多個(gè)弱引用束析,你可以傳入多個(gè)變量)艳馒,@strongify讓你創(chuàng)建一個(gè)對(duì)之前傳入@weakify對(duì)象的強(qiáng)引用。這樣就解決了循環(huán)引用的問題

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

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

使用系統(tǒng)的方法請(qǐ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請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)

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

//rac網(wǎng)絡(luò)請(qǐng)求
-(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ā)送信號(hào)
                [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);
    }];

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



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

flattenMap---獲取信號(hào)中的信號(hào)

把上面的代碼寫成這樣布讹,就可以獲取到數(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)訂閱到的信號(hào),是你想要的數(shù)據(jù)了训堆。

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

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

回到主線程---deliverOn

因?yàn)樾盘?hào)的流轉(zhuǎn)及操作都是在block中完成的,也就是說大部分操作都是在子線程中執(zhí)行的操作睡扬,但是有個(gè)時(shí)候需要回到主線程完成一些事情盟蚣,比如黍析,請(qǐng)求到數(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中顯示出來,而且可以看到訂閱信號(hào)的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);
     }];
信號(hào)節(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的作用:如果前面信號(hào)在設(shè)定的時(shí)間內(nèi)沒有變化時(shí),throttle就會(huì)把信號(hào)傳到下面的事件中去瘟芝。

使用系統(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信號(hào)對(duì)象晤郑,

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

GitHub下載地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市圆到,隨后出現(xiàn)的幾起案子怎抛,更是在濱河造成了極大的恐慌,老刑警劉巖抽诉,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吐绵,居然都是意外死亡迹淌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門己单,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唉窃,“玉大人,你說我怎么就攤上這事纹笼∥品荩” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵廷痘,是天一觀的道長蔓涧。 經(jīng)常有香客問我,道長笋额,這世上最難降的妖魔是什么元暴? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮兄猩,結(jié)果婚禮上茉盏,老公的妹妹穿的比我還像新娘鉴未。我一直安慰自己,他們只是感情好鸠姨,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布铜秆。 她就那樣靜靜地躺著,像睡著了一般讶迁。 火紅的嫁衣襯著肌膚如雪连茧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天添瓷,我揣著相機(jī)與錄音梅屉,去河邊找鬼值纱。 笑死鳞贷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的虐唠。 我是一名探鬼主播搀愧,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼疆偿!你這毒婦竟也來了咱筛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤杆故,失蹤者是張志新(化名)和其女友劉穎迅箩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體处铛,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饲趋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撤蟆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奕塑。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖家肯,靈堂內(nèi)的尸體忽然破棺而出龄砰,到底是詐尸還是另有隱情,我是刑警寧澤讨衣,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布换棚,位于F島的核電站,受9級(jí)特大地震影響反镇,放射性物質(zhì)發(fā)生泄漏固蚤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一愿险、第九天 我趴在偏房一處隱蔽的房頂上張望颇蜡。 院中可真熱鬧价说,春花似錦、人聲如沸风秤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缤弦。三九已至领迈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碍沐,已是汗流浹背狸捅。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留累提,地道東北人尘喝。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像斋陪,于是被迫代替她去往敵國和親朽褪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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