繼續(xù)完成RAC的坑
前言
經(jīng)過上篇文章的學(xué)習(xí)腋逆,相信不少讀者已經(jīng)熟悉了RAC的基本用法研侣,可以嘗試在以后的開發(fā)中不用add target
語句了回溺。這篇文章將稍微深入一點了解RAC的更多功能以及適用場合液斜。
什么是信號
RAC的核心就是信號矫膨,即RACSignal
。
信號可以看做是傳遞信號的工具瘦材,當(dāng)數(shù)據(jù)變化時厅须,信號就會發(fā)送改變的信息,以通知信號的訂閱者執(zhí)行方法食棕。
熱/冷信號
默認一個信號都是冷信號朗和,也就是值改變了错沽,也不會觸發(fā),只有訂閱了這個信號例隆,這個信號才會變?yōu)闊嵝盘柹啵蹈淖兞瞬艜|發(fā)。
自己動手寫一個RACSignal
//創(chuàng)建信號
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"signal"];
[subscriber sendCompleted];
return nil;
}];
//訂閱信號
[signal subscribeNext:^(id x) {
NSLog(@"x = %@", x);
} error:^(NSError *error) {
NSLog(@"error = %@", error);
} completed:^{
NSLog(@"completed");
}];
這是一個信號從創(chuàng)建到接收的完整過程镀层,我們接下來看看控制臺輸出了什么镰禾。
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)建信號時我們sent了一個signal唱逢,在我們訂閱subscribeNext
時存儲在x中的就是這個字符串signal吴侦。從這里看出來,不但我們可以給訂閱者傳遞字符串坞古,只要是一個類一個對象我們都可以傳遞备韧。
另一方面控制臺輸出了completed說明訂閱信號部分的completed塊下得方法也被執(zhí)行了,這是因為餓哦在創(chuàng)建時發(fā)送完signal后又發(fā)送了一個completed痪枫。同理织堂,error下得方法我們也可以這樣調(diào)用。
融匯貫通一下奶陈,我們之前學(xué)的所有RAC的用法就是一個創(chuàng)建信號訂閱信號的過程易阳!
信號的處理
map
這里的map不是地圖,而是映射的意思吃粒,就是創(chuàng)建一個訂閱者的映射并且返回數(shù)據(jù)潦俺,具體用法我們來看代碼。
[[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
還是之前那個監(jiān)聽textfild編輯變化的例子事示,可以看到,當(dāng)信號被訂閱變成熱信號后僻肖,這里的map構(gòu)造的映射塊value的值就是控件中的字符變化肖爵,而訂閱者x的值就是映射者的返回值1。
根據(jù)這個功能我們就可以對我們監(jiān)測的東西和我們需求的東西進行轉(zhuǎn)換檐涝。比如監(jiān)聽了字符串變化遏匆,我們需要的時變化后的字符串長度而不是變化的字符串本身,則可以在map的返回值中返回text.length
谁榜,就可以實時捕獲到字符串長度;甚至做一個映射表凡纳,將各個變化進行一對一或者一對多或者多對一的處理窃植。
filter
filter就是過濾,它可以幫助你篩選出你需要的信號變化荐糜。
[[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
上述例子是在字符串長度大于3時才會輸出變換后的字符串葛超。
take/skip/repeat
take是獲取,skip是跳過延塑,這兩個方法后面跟著的都是NSInteger绣张。所以take 2
就是獲取前兩個信號,skip 2
就是跳過前兩個关带。repeat是重復(fù)發(fā)送信號侥涵。
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");
}];
這個demo只會輸出前兩個信號1和2還有完成信號completed,skip,repeat同理宋雏。
相似的還有takeLast
takeUntil
takeWhileBlock
skipWhileBlock
skipUntilBlock
repeatWhileBlock
都可以根據(jù)字面意思來理解芜飘。
delay
延時信號,顧名思義磨总,即延遲發(fā)送信號嗦明。
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
看時間可以發(fā)現(xiàn)訂閱者延遲了2秒才收到信號打印出x的值。PS:還有0.2s誤差是因為運行到不同代碼行的時間差
throttle
節(jié)流蚪燕,在我們做搜索框的時候娶牌,有時候需求的時實時搜索,即用戶每每輸入字符馆纳,view都要求展現(xiàn)搜索結(jié)果诗良。這時如果用戶搜索的字符串較長,那么由于網(wǎng)絡(luò)請求的延時可能造成UI顯示錯誤厕诡,并且多次不必要的請求還會加大服務(wù)器的壓力累榜,這顯然是不合理的,此時我們就需要用到節(jié)流灵嫌。
[[[self.textFild rac_textSignal] throttle:0.5] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
加了節(jié)流管道壹罚,后面跟上了類型為NSTimeInterval的參數(shù)后,只有0.5S內(nèi)信號不產(chǎn)生變化才會發(fā)送請求寿羞,這樣快速的輸入也不會造成多次輸出猖凛。
distinctUntilChanged
網(wǎng)絡(luò)請求中為了減輕服務(wù)器壓力,無用的請求我們應(yīng)該盡可能不發(fā)送绪穆。distinctUntilChanged
的作用是使RAC不會連續(xù)發(fā)送兩次相同的信號辨泳,這樣就解決了這個問題。
[[[self.textFild rac_textSignal] distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
timeout
超時信號玖院,當(dāng)超出限定時間后會給訂閱者發(fā)送error信號菠红。
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)建信號是限定了延遲3秒發(fā)送,但是加了timeout2秒的限定难菌,所以這一定是一個超時信號试溯。這個信號被訂閱后,由于超時郊酒,不會執(zhí)行訂閱成功的輸出x方法遇绞,而是跳到error的塊輸出了錯誤信息键袱。timeout在用RAC封裝網(wǎng)絡(luò)請求時可以節(jié)省不少的代碼量。
ignore
忽略信號摹闽,指定一個任意類型的量(可以是字符串蹄咖,數(shù)組等),當(dāng)需要發(fā)送信號時講進行判斷付鹿,若相同則該信號會被忽略發(fā)送澜汤。
[[[self.textFild rac_textSignal] ignore:@"good"] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
總結(jié)
這篇文章比上一篇稍稍深入了RAC的附加功能,但還有很多例如扁平映射flattenMap
倘屹,Signal of Signals都沒有提到银亲,RAC的東西實在太多太多,我說的也僅僅是九牛一毛纽匙。我將繼續(xù)研究RAC的深入用法务蝠,并發(fā)文給大家介紹。如果文中有什么錯誤烛缔,也希望大家給我指出來馏段,我將萬分感謝。也歡迎來我的博客看看践瓷。