RAC使用函數(shù)響應(yīng)式編程的思想抽碌,將我們平時(shí)用到的按鈕點(diǎn)擊事件、KVO决瞳、代理咬展、通知等等封裝起來,處理業(yè)務(wù)邏輯的代碼放到一起瞒斩,使代碼更加的簡潔、高內(nèi)聚涮总、低耦合胸囱,那么我們來看看它的具體使用。
一瀑梗、RAC的基本使用
RAC和KVO
//使用RAC來監(jiān)聽字符串myString的變化
[RACObserve(self, myString) subscribeNext:^(id _Nullable x) {
NSLog(@"myString值發(fā)生變化后的新值:%@",x);
}];
一句代碼就可以代替KVO
,代碼和功能在一起烹笔,寫起來方便,簡單易讀抛丽。
-
RACObserve(TARGET, KEYPATH)
:RAC
提供的宏定義谤职,用來監(jiān)聽值的變化,返回RACSignal
類型的信號(hào)亿鲜,有了這個(gè)宏定義返回的信號(hào)允蜈,就可以訂閱該信號(hào),變化后的值蒿柳。 -
subscribeNext:
:訂閱信號(hào)饶套,只有訂閱了信號(hào)才可以收到值的變化。
RAC和通知
//監(jiān)聽鍵盤彈出的通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
//處理接收到的通知
NSLog(@"%@",x);
}];
rac_addObserverForName: object:
:也可以添加開發(fā)中自己注冊(cè)的通知垒探,添加監(jiān)聽通知的方法妓蛮,寫在NSNotificationCenter
分類中。RAC
中有很多的分類實(shí)現(xiàn)不同的方法圾叼。
RAC和代理
//添加UITextFieldDelegate代理方法textFieldDidBeginEditing:信號(hào)
[[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] subscribeNext:^(RACTuple * _Nullable x) {
//RACTuple:元組類型
NSLog(@"%@",x);
}];
//實(shí)現(xiàn)代理
self.textField.delegate = self;
rac_signalForSelector:fromProtocol:
添加代理方法信號(hào)蛤克。
- 值得注意的是,接收訂閱信號(hào)的參數(shù)是
RACTuple
元組類型夷蚊,熟悉swift
語法的話對(duì)元組類型一定不陌生构挤,元組是把多個(gè)值組合成一個(gè)復(fù)合值。元組內(nèi)的值可以是任意類型惕鼓,并不要求是相同類型儿倒。以下是上面代碼接受到信號(hào)的打印信息,可以看一下元組是什么樣子的:
<RACTuple: 0x6000018a5960> (
<UITextField: 0x7f966fd6b3d0; frame = (72 219; 270 34); text = ''; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x60000143dce0>; layer = <CALayer: 0x600001ad9240>>,
)
UIButton
//按鈕點(diǎn)擊信號(hào)
@weakify(self);//防止循環(huán)引用的問題
[[self.myButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
@strongify(self);//暫時(shí)強(qiáng)引用
//接收到點(diǎn)擊信號(hào)的響應(yīng),
if(self.textField.text.length == 0) {
NSLog(@"請(qǐng)先輸入名稱");
}else {
//...
}
}];
rac_signalForControlEvents :
:UIButton
的分類方法,產(chǎn)生點(diǎn)擊信號(hào)夫否。
- 在訂閱信號(hào)中進(jìn)行
UI
的綁定彻犁,這種思想在MVVM+RAC
的架構(gòu)中非常重要,MVVM
中通過block
回調(diào)可以完成ViewModel
向UI
層數(shù)據(jù)傳遞凰慈,使用rac
進(jìn)行UI
綁定汞幢,就可以完成UI
層向ViewModel
層的數(shù)據(jù)傳輸,從而實(shí)現(xiàn)雙向綁定微谓。
UITextField
//輸入框文字改變信號(hào)
[self.textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
//打印當(dāng)前textField的text
NSLog(@"%@",x);
}];
rac_textSignal
:輸入框輸入的文字發(fā)生改變的信號(hào)森篷,訂閱這個(gè)信號(hào)可以處理文字長度,輸入格式等豺型。
手勢(shì)
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
self.label.userInteractionEnabled = YES;
[self.label addGestureRecognizer:tap];
[tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
NSLog(@"%@",x);
}];
rac_gestureSignal
:手勢(shì)觸發(fā)信號(hào)仲智。
序列 sequence
數(shù)組遍歷
NSArray *nameArray = @[@"Niki",@"Pan",@"Ding",@"Jiao"];
//數(shù)組遍歷
[nameArray.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);//依次打印數(shù)組元素
}];
NSDictionary *dict = @{@"name":@"Niki",@"age":@"18",@"number":@"999"};
//遍歷字典
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
//元組類型
NSLog(@"%@",x);
//RACTwoTuple繼承自RACTuple,表示有兩個(gè)值的元組
RACTwoTuple *tuple = (RACTwoTuple *)x;
NSLog(@"key == %@ , value = %@",tuple[0],tuple[1]);
}];
集合類型在RAC
中都封裝成了序列姻氨,通過訪問rac_sequence
屬性得到序列钓辆。
二、RAC中的高階函數(shù)
-
信號(hào)映射:
map
和flattenMap
,把原有信號(hào)中的值映射成新的值肴焊。
-
map:
方法返回依舊是一個(gè)信號(hào)RACSignal
類型前联,如下代碼,將rac_textSignal
信號(hào)中的字符串經(jīng)過map
映射處理成字符串的長度娶眷。注意:map
的block
中必須要返回對(duì)象類型的數(shù)據(jù)似嗤。
[[self.passField.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
return @(value.length);
}] subscribeNext:^(id _Nullable x) {
NSLog(@"映射后的新值:%@",x);//輸出字符串長度
}];
-
flattenMap:
把源信號(hào)的內(nèi)容映射成一個(gè)新的信號(hào),信號(hào)可以是任意類型届宠。
[[self.passField.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
//返回RACSignal類型
return [RACReturnSignal return:@(value.length)];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"映射后的新值:%@",x);
}];
-
信號(hào)過濾:
filter
,ignore
,distinctUntilChanged
-
filter
:獲取滿足條件的信號(hào) -
ignore
:內(nèi)部調(diào)用了filter
烁落,忽略掉ignore
傳入的參數(shù)。 -
distinctUntilChanged
:跟函數(shù)名字面意思一樣豌注,直到值和上一次有區(qū)別才會(huì)發(fā)出信號(hào)顽馋,忽略的是和上一次值一樣的信號(hào)。經(jīng)常用于UI
的刷新幌羞,值發(fā)生變化的時(shí)候才刷新寸谜。
下面依次來看代碼示例:
//filter
[[self.passField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
//輸入字符串長度大于3
return value.length > 3;
}] subscribeNext:^(id _Nullable x) {
//獲取到輸入字符串長度大于3的信號(hào)
//當(dāng)輸入字符串長度大于3才會(huì)在這里打印
NSLog(@"%@",x);
}];
//ignore
[[self.passField.rac_textSignal ignore:@"n"] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);//輸入n,這里收不到信號(hào)
}];
//distinctUntilChanged
RACSubject *subject = [RACSubject subject];
[[subject distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@", x);//收到的信號(hào)依次是a b c,第三次發(fā)送的b被忽略了
}];
// 發(fā)送信號(hào)
[subject sendNext:@"a"];
[subject sendNext:@"b"];
[subject sendNext:@"b"];
[subject sendNext:@"c"];
-
信號(hào)合并:
combineLatest
,reduce
,merge
,zipWith
-
combineLatest
:將多個(gè)信號(hào)合并起來属桦,并且拿到各個(gè)信號(hào)的最新值,必須每個(gè)合并的signal至少都有過一次sendNext熊痴,才會(huì)觸發(fā)合并的信號(hào)。 -
reduce
:把combineLatest
的元組聚合成一個(gè)值發(fā)送出去聂宾,相當(dāng)于對(duì)combineLatest
的進(jìn)一步加工果善,必須每個(gè)合并的signal至少都有過一次sendNext,才會(huì)觸發(fā)合并的信號(hào)系谐。 -
merge
:把多個(gè)信號(hào)合并成一個(gè)信號(hào)巾陕,任何一個(gè)信號(hào)發(fā)送數(shù)據(jù)讨跟,都能監(jiān)聽到。 -
zip
:把最近發(fā)出的信號(hào)包裝成元組發(fā)出鄙煤。當(dāng)每個(gè)信號(hào)同事發(fā)出信號(hào)內(nèi)容晾匠,才會(huì)發(fā)出信號(hào)。
//combineLatest
//創(chuàng)建三個(gè)信號(hào)
RACSubject *s1 = [RACSubject subject];
RACSubject *s2 = [RACSubject subject];
RACSubject *s3 = [RACSubject subject];
//合并三個(gè)信號(hào)
RACSignal *combineSg = [RACSignal combineLatest:@[s1,s2,s3]];
//訂閱合并信號(hào)
[combineSg subscribeNext:^(id _Nullable x) {
//當(dāng)三個(gè)信號(hào)都有一次發(fā)送的時(shí)候才能收到聚合信號(hào)
//這里收到是一個(gè)元組類型梯刚,三個(gè)元素分別為三個(gè)信號(hào)的最新值
NSLog(@"%@",x);
}];
//發(fā)送信號(hào)
[s1 sendNext:@"a"];
[s2 sendNext:@"1"];
[s3 sendNext:@"!"];
[s1 sendNext:@"b"];
[s2 sendNext:@"2"];
[s3 sendNext:@"@"];
[s1 sendNext:@"c"];
[s2 sendNext:@"3"];
[s3 sendNext:@"#"];
//reduce
RACSubject *s1 = [RACSubject subject];
RACSubject *s2 = [RACSubject subject];
RACSubject *s3 = [RACSubject subject];
RACSignal *reduceSg = [RACSignal combineLatest:@[s1,s2,s3] reduce:^(id value1,id value2,id value3){
//value1 value2 value3為三個(gè)信號(hào)的最新值
return [NSString stringWithFormat:@"%@,%@,%@",value1,value2,value3];
}];
//訂閱聚合信號(hào)
[reduceSg subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//發(fā)送信號(hào)
[s1 sendNext:@"a"];
[s2 sendNext:@"1"];
[s3 sendNext:@"!"];
[s1 sendNext:@"b"];
[s2 sendNext:@"2"];
[s3 sendNext:@"@"];
[s1 sendNext:@"c"];
[s2 sendNext:@"3"];
[s3 sendNext:@"#"];
/*打印輸出結(jié)果,三個(gè)信號(hào)都發(fā)送一次sendNext之后才會(huì)收到第一次聚合信號(hào)
a,1,!
b,1,!
b,2,!
b,2,@
c,2,@
c,3,@
c,3,#
*/
//merge
RACSubject *s1 = [RACSubject subject];
RACSubject *s2 = [RACSubject subject];
RACSubject *s3 = [RACSubject subject];
//合并三個(gè)信號(hào)
RACSignal *mergeSg = [RACSignal merge:@[s1,s2,s3]];
[mergeSg subscribeNext:^(id _Nullable x) {
//收到九次信號(hào)凉馆,每次打印當(dāng)前信號(hào)最新值
NSLog(@"%@",x);
}];
[s1 sendNext:@"a"];
[s2 sendNext:@"1"];
[s3 sendNext:@"!"];
[s1 sendNext:@"b"];
[s2 sendNext:@"2"];
[s3 sendNext:@"@"];
[s1 sendNext:@"c"];
[s2 sendNext:@"3"];
[s3 sendNext:@"#"];
//zip
RACSubject *s1 = [RACSubject subject];
RACSubject *s2 = [RACSubject subject];
RACSubject *s3 = [RACSubject subject];
RACSignal *zipSg = [RACSignal zip:@[s1,s2,s3]];
[zipSg subscribeNext:^(id _Nullable x) {
/*收到兩次信號(hào)
( a, 1, !, ) (b, 3, @, )
*/
NSLog(@"%@",x);
}];
[s1 sendNext:@"a"];
[s2 sendNext:@"1"];
[s3 sendNext:@"!"];
[s1 sendNext:@"b"];
// [s2 sendNext:@"2"];
[s3 sendNext:@"@"];
[s1 sendNext:@"c"];
[s2 sendNext:@"3"];
[s3 sendNext:@"#"];
-
信號(hào)連接:
concat
,then
-
concat
:信號(hào)連接起來,按順序響應(yīng)信號(hào)亡资。 -
then
:只收到then返回的信號(hào)澜共,之前的信號(hào)會(huì)被忽略
//concat
RACSignal *s1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"信號(hào)1"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *s2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"信號(hào)2"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *contactSg = [s1 concat:s2];
[contactSg subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);//依次打印 信號(hào)1 信號(hào)2
}];
//then
RACSignal *s1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"信號(hào)1"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *s2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"信號(hào)2"];
[subscriber sendCompleted];
return nil;
}];
[[s2 then:^RACSignal * _Nonnull{
return s1;
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);//只收到信號(hào)1,第一個(gè)信號(hào)會(huì)被忽略
}];
-
信號(hào)操作時(shí)間:
timeout
,interval
,dely
-
timeout
:超時(shí)信號(hào)锥腻,超過設(shè)定時(shí)間后會(huì)收到錯(cuò)誤信號(hào) -
dely
:延時(shí)發(fā)送信號(hào)
//設(shè)置signal的超時(shí)時(shí)間是2秒
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//延時(shí)三秒發(fā)送信號(hào)
[[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);//2秒后打印信息嗦董,因?yàn)榘l(fā)送信號(hào)延時(shí)了3秒
}];
- 還有其他的,持續(xù)更新瘦黑。
RAC信號(hào)響應(yīng)流程
- 信號(hào)聲命周期:
創(chuàng)建信號(hào)-訂閱信號(hào)-發(fā)送信號(hào)-銷毀信號(hào) -
信號(hào)響應(yīng)流程分析