RAC稍深入-適合新手學(xué)習(xí)RAC

繼續(xù)完成RAC的坑


前言

經(jīng)過(guò)上篇文章的學(xué)習(xí),相信不少讀者已經(jīng)熟悉了RAC的基本用法,可以嘗試在以后的開發(fā)中不用add target語(yǔ)句了。這篇文章將稍微深入一點(diǎn)了解RAC的更多功能以及適用場(chǎng)合。

什么是信號(hào)

RAC的核心就是信號(hào),即RACSignal

信號(hào)可以看做是傳遞信號(hào)的工具,當(dāng)數(shù)據(jù)變化時(shí),信號(hào)就會(huì)發(fā)送改變的信息,以通知信號(hào)的訂閱者執(zhí)行方法。

熱/冷信號(hào)

默認(rèn)一個(gè)信號(hào)都是冷信號(hào),也就是值改變了,也不會(huì)觸發(fā),只有訂閱了這個(gè)信號(hào),這個(gè)信號(hào)才會(huì)變?yōu)闊嵝盘?hào),值改變了才會(huì)觸發(fā)。

自己動(dòng)手寫一個(gè)RACSignal

//創(chuàng)建信號(hào)
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"signal"];
    [subscriber sendCompleted];
    return nil;
}];

//訂閱信號(hào)
[signal subscribeNext:^(id x) {
    NSLog(@"x = %@", x);
} error:^(NSError *error) {
    NSLog(@"error = %@", error);
} completed:^{
    NSLog(@"completed");
}];

這是一個(gè)信號(hào)從創(chuàng)建到接收的完整過(guò)程,我們接下來(lái)看看控制臺(tái)輸出了什么。

2016-01-05 14:33:06.106 RACStudyTest[895:38671] x = signal
2016-01-05 14:33:06.106 RACStudyTest[895:38671] completed

可以看到,創(chuàng)建信號(hào)時(shí)我們sent了一個(gè)signal,在我們訂閱subscribeNext時(shí)存儲(chǔ)在x中的就是這個(gè)字符串signal。從這里看出來(lái),不但我們可以給訂閱者傳遞字符串,只要是一個(gè)類一個(gè)對(duì)象我們都可以傳遞。

另一方面控制臺(tái)輸出了completed說(shuō)明訂閱信號(hào)部分的completed塊下得方法也被執(zhí)行了,這是因?yàn)轲I哦在創(chuàng)建時(shí)發(fā)送完signal后又發(fā)送了一個(gè)completed。同理,error下得方法我們也可以這樣調(diào)用。

融匯貫通一下,我們之前學(xué)的所有RAC的用法就是一個(gè)創(chuàng)建信號(hào)訂閱信號(hào)的過(guò)程!

信號(hào)的處理

map

這里的map不是地圖,而是映射的意思,就是創(chuàng)建一個(gè)訂閱者的映射并且返回?cái)?shù)據(jù),具體用法我們來(lái)看代碼。

[[self.textFild.rac_textSignal map:^id(id value) {
    NSLog(@"%@", value);
    return @1;
}] subscribeNext:^(id x) {
    NSLog(@"%@", x);
}];

在TextFild控件中輸入good,輸出:

2016-01-05 15:02:15.180 RACStudyTest[1418:57245] 1
2016-01-05 15:02:21.710 RACStudyTest[1418:57245] g
2016-01-05 15:02:21.711 RACStudyTest[1418:57245] 1
2016-01-05 15:02:22.954 RACStudyTest[1418:57245] go
2016-01-05 15:02:22.955 RACStudyTest[1418:57245] 1
2016-01-05 15:02:23.464 RACStudyTest[1418:57245] goo
2016-01-05 15:02:23.464 RACStudyTest[1418:57245] 1
2016-01-05 15:02:23.705 RACStudyTest[1418:57245] good
2016-01-05 15:02:23.705 RACStudyTest[1418:57245] 1  

還是之前那個(gè)監(jiān)聽textfild編輯變化的例子,可以看到,當(dāng)信號(hào)被訂閱變成熱信號(hào)后,這里的map構(gòu)造的映射塊value的值就是控件中的字符變化,而訂閱者x的值就是映射者的返回值1。

根據(jù)這個(gè)功能我們就可以對(duì)我們監(jiān)測(cè)的東西和我們需求的東西進(jìn)行轉(zhuǎn)換。比如監(jiān)聽了字符串變化,我們需要的時(shí)變化后的字符串長(zhǎng)度而不是變化的字符串本身,則可以在map的返回值中返回text.length,就可以實(shí)時(shí)捕獲到字符串長(zhǎng)度;甚至做一個(gè)映射表,將各個(gè)變化進(jìn)行一對(duì)一或者一對(duì)多或者多對(duì)一的處理。

filter

filter就是過(guò)濾,它可以幫助你篩選出你需要的信號(hào)變化。

[[self.textFild.rac_textSignal filter:^BOOL(NSString *value) {
    return [value length] > 3;
}] subscribeNext:^(id x) {
    NSLog(@"x = %@", x);
}];

輸入goodnight,輸出:

2016-01-05 15:18:20.492 RACStudyTest[1490:66721] x = good
2016-01-05 15:18:27.917 RACStudyTest[1490:66721] x = goodn
2016-01-05 15:18:28.129 RACStudyTest[1490:66721] x = goodni
2016-01-05 15:18:28.433 RACStudyTest[1490:66721] x = goodnig
2016-01-05 15:18:28.930 RACStudyTest[1490:66721] x = goodnigh
2016-01-05 15:18:29.155 RACStudyTest[1490:66721] x = goodnight

上述例子是在字符串長(zhǎng)度大于3時(shí)才會(huì)輸出變換后的字符串。

take/skip/repeat

take是獲取,skip是跳過(guò),這兩個(gè)方法后面跟著的都是NSInteger。所以take 2就是獲取前兩個(gè)信號(hào),skip 2就是跳過(guò)前兩個(gè)。repeat是重復(fù)發(fā)送信號(hào)。

RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"2"];
    [subscriber sendNext:@"3"];
    [subscriber sendNext:@"4"];
    [subscriber sendNext:@"5"];
    [subscriber sendCompleted];
    return nil;
}] take:2];

[signal subscribeNext:^(id x) {
    NSLog(@"%@", x);
}completed:^{
    NSLog(@"completed");
}];

這個(gè)demo只會(huì)輸出前兩個(gè)信號(hào)1和2還有完成信號(hào)completed,skip,repeat同理。

相似的還有takeLast takeUntil takeWhileBlock skipWhileBlock skipUntilBlock repeatWhileBlock都可以根據(jù)字面意思來(lái)理解。

delay

延時(shí)信號(hào),顧名思義,即延遲發(fā)送信號(hào)。

RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"delay"];
    [subscriber sendCompleted];
    return nil;
}] delay:2];

NSLog(@"tag");

[signal subscribeNext:^(id x) {
    NSLog(@"%@", x);
}];

輸出:

2016-01-05 15:27:55.908 RACStudyTest[1543:71256] tag
2016-01-05 15:27:58.102 RACStudyTest[1543:71256] delay

看時(shí)間可以發(fā)現(xiàn)訂閱者延遲了2秒才收到信號(hào)打印出x的值。PS:還有0.2s誤差是因?yàn)檫\(yùn)行到不同代碼行的時(shí)間差

throttle

節(jié)流,在我們做搜索框的時(shí)候,有時(shí)候需求的時(shí)實(shí)時(shí)搜索,即用戶每每輸入字符,view都要求展現(xiàn)搜索結(jié)果。這時(shí)如果用戶搜索的字符串較長(zhǎng),那么由于網(wǎng)絡(luò)請(qǐng)求的延時(shí)可能造成UI顯示錯(cuò)誤,并且多次不必要的請(qǐng)求還會(huì)加大服務(wù)器的壓力,這顯然是不合理的,此時(shí)我們就需要用到節(jié)流。

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

加了節(jié)流管道,后面跟上了類型為NSTimeInterval的參數(shù)后,只有0.5S內(nèi)信號(hào)不產(chǎn)生變化才會(huì)發(fā)送請(qǐng)求,這樣快速的輸入也不會(huì)造成多次輸出。

distinctUntilChanged

網(wǎng)絡(luò)請(qǐng)求中為了減輕服務(wù)器壓力,無(wú)用的請(qǐng)求我們應(yīng)該盡可能不發(fā)送。distinctUntilChanged的作用是使RAC不會(huì)連續(xù)發(fā)送兩次相同的信號(hào),這樣就解決了這個(gè)問(wèn)題。

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

timeout

超時(shí)信號(hào),當(dāng)超出限定時(shí)間后會(huì)給訂閱者發(fā)送error信號(hào)。

RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
        [subscriber sendNext:@"delay"];
        [subscriber sendCompleted];
    }];
    return nil;
}] timeout:2 onScheduler:[RACScheduler mainThreadScheduler]];

[signal subscribeNext:^(id x) {
    NSLog(@"%@", x);
} error:^(NSError *error) {
    NSLog(@"%@", error);
}];

輸出:

2016-01-05 15:41:58.686 RACStudyTest[1604:76716] Error Domain=RACSignalErrorDomain Code=1 "The operation couldn’t be completed. (RACSignalErrorDomain error 1.)"

由于在創(chuàng)建信號(hào)是限定了延遲3秒發(fā)送,但是加了timeout2秒的限定,所以這一定是一個(gè)超時(shí)信號(hào)。這個(gè)信號(hào)被訂閱后,由于超時(shí),不會(huì)執(zhí)行訂閱成功的輸出x方法,而是跳到error的塊輸出了錯(cuò)誤信息。timeout在用RAC封裝網(wǎng)絡(luò)請(qǐng)求時(shí)可以節(jié)省不少的代碼量。

ignore

忽略信號(hào),指定一個(gè)任意類型的量(可以是字符串,數(shù)組等),當(dāng)需要發(fā)送信號(hào)時(shí)講進(jìn)行判斷,若相同則該信號(hào)會(huì)被忽略發(fā)送。

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

總結(jié)

這篇文章比上一篇稍稍深入了RAC的附加功能,但還有很多例如扁平映射flattenMap,Signal of Signals都沒有提到,RAC的東西實(shí)在太多太多,我說(shuō)的也僅僅是九牛一毛。我將繼續(xù)研究RAC的深入用法,并發(fā)文給大家介紹。如果文中有什么錯(cuò)誤,也希望大家給我指出來(lái),我將萬(wàn)分感謝。也歡迎來(lái)我的博客看看。

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

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

  • RAC使用測(cè)試Demo下載:github.com/FuWees/WPRACTestDemo 1.ReactiveC...
    FuWees閱讀 6,489評(píng)論 3 10
  • 標(biāo)簽: iOS RAC 概述 ReactiveCocoa是一個(gè)函數(shù)響應(yīng)式編程框架,它能讓我們脫離Cocoa AP...
    GodyZ閱讀 7,636評(píng)論 16 97
  • 作為一個(gè)iOS開發(fā)者,你寫的每一行代碼幾乎都是在相應(yīng)某個(gè)事件,例如按鈕的點(diǎn)擊,收到網(wǎng)絡(luò)消息,屬性的變化(通過(guò)KVO...
    jiajia1118閱讀 819評(píng)論 0 2
  • RAC支持的UI控件 RACCommand RACCommand類用于表示事件的執(zhí)行,一般來(lái)說(shuō)是在UI上的某些動(dòng)作...
    花前月下閱讀 2,780評(píng)論 0 5
  • 最近有位編輯找我,問(wèn)我認(rèn)識(shí)不認(rèn)識(shí)魔云獸,我說(shuō)我倆是好朋友呀!(我真的沒吹牛,我倆真的是好朋友,不相信可以去問(wèn)他,不...
    鼴鼠的土豆閱讀 1,261評(píng)論 4 32