最近一直斷斷續續學習關於ReactiveCocoa的知識內容,對於它的一些基礎內容將通過本文進行一個總結,主要是一些入門知識 一:RACSignal一些運用 @interface RACSignalTestViewController () @property(nonatomic,strong)RA
最近一直斷斷續續學習關於ReactiveCocoa的知識內容,對於它的一些基礎內容將通過本文進行一個總結,主要是一些入門知識
一:RACSignal一些運用
@interface RACSignalTestViewController () @property(nonatomic,strong)RACSignal *mySignal,*secondSingl; @end
-(RACSignal *)mySignal { if (!_mySignal) { _mySignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@10]; [subscriber sendCompleted]; return nil; }]; } return _mySignal; } -(RACSignal *)secondSingl { if (!_secondSingl) { _secondSingl=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@20]; [subscriber sendCompleted]; return nil; }]; } return _secondSingl; }
先創建兩個RACSignal的內容;將用於接下來的一些操作
//map運用 返回的值作為next的參數 [[self.mySignal map:^id(NSNumber *value) { return [value integerValue]>5?@"踏浪帥":@"有點小"; }] subscribeNext:^(NSString *str) { NSLog(@"map處理完成的值為:%@",str); }]; //filter:過濾信號,使用它可以獲取滿足條件的信號. [[self.mySignal filter:^BOOL(NSNumber *item) { return [item integerValue]>5; }] subscribeNext:^(NSNumber *x) { NSLog(@"filter當前的值%ld",[x integerValue]); }]; //ignore:忽略完某些值的信號.當答合被ignore的值時就不會執行next [[self.mySignal ignore:@10] subscribeNext:^(id x) { NSLog(@"ignore當前的值:%@",x); }]; //distinctUntilChanged:當上一次的值和當前的值有明顯的變化就會發出信號,否則會被忽略掉。 [[self.mySignal distinctUntilChanged] subscribeNext:^(id x) { NSLog(@"distinctUntilChanged當前的值:%@",x); }]; //take:從開始一共取N次的信號 //takeLast:取最後N次的信號,前提條件,訂閱者必須調用完成,因為只有完成,就知道總共有多少信號. //takeUntil:(RACSignal *):獲取信號直到某個信號執行完成 //skip:(NSUInteger):跳過幾個信號,不接受。
運行結果:
MobileProject[885:18784] map處理完成的值為:踏浪帥 2016-02-02 16:03:07.643 MobileProject[885:18784] filter當前的值10 2016-02-02 16:03:07.644 MobileProject[885:18784] distinctUntilChanged當前的值:10
1.2:一些組合的操作
//concat:按一定順序拼接信號,當多個信號發出的時候,有順序的接收信號 RACSignal *concatSignal=[self.mySignal concat:self.secondSingl]; [concatSignal subscribeNext:^(id x) { NSLog(@"concat拼接的值:%@",x); }]; //then:用於連接兩個信號,當第一個信號完成,才會連接then返回的信號 [[self.mySignal then:^RACSignal *{ @strongify(self); return self.secondSingl; }] subscribeNext:^(id x) { //// 只能接收到第二個信號的值,也就是then返回信號的值 NSLog(@"then當前的值為:%@",x); }]; //merge:把多個信號合併為一個信號,任何一個信號有新值的時候就會調用 RACSignal *mergeSignal=[self.mySignal merge:self.secondSingl]; [mergeSignal subscribeNext:^(id x) { NSLog(@"merge當前的值為:%@",x); }]; //combineLatest:將多個信號合併起來,並且拿到各個信號的最新的值,必須每個合併的signal至少都有過一次sendNext,兩個信號的內容合併成一個元組RACTuple,才會觸發合併的信號。 RACSignal *combineLatestSignal=[self.mySignal combineLatestWith:self.secondSingl]; [combineLatestSignal subscribeNext:^(id x) { NSLog(@"combineLastest當前的值為:%@",x); }]; //zipWith:把兩個信號壓縮成一個信號,只有當兩個信號同時發出信號內容時,並且把兩個信號的內容合併成一個元組RACTuple,才會觸發壓縮流的next事件。 RACSignal *zipWithSignal=[self.mySignal zipWith:self.secondSingl]; [zipWithSignal subscribeNext:^(RACTuple *tuple) { NSLog(@"zipWith當前的值為:%@",tuple); NSLog(@"zipWith中的RACTuple共有幾個值:%ld",tuple.count); NSLog(@"zipWith中的RACTuple第一個值為:%@",tuple.first); NSLog(@"zipWith中的RACTuple最後一個值為:%@",tuple.last); }]; //reduce聚合:用於信號發出的內容是元組,把信號發出元組的值聚合成一個值 特別是combineLatestWith,zipWith這種返回元組的RACTuple,reduceblcok中的參數,有多少信號組合,reduceblcok就有多少參數,每個參數就是之前信號發出的內容 RACSignal *reduceSignal=[RACSignal combineLatest:@[self.mySignal,self.secondSingl] reduce:^id(NSNumber *num1 ,NSNumber *num2){ NSLog(@"combineLastest結合reduct的第一個值為:%ld 第二個值為:%ld",[num1 integerValue],[num2 integerValue]); return ([num1 integerValue]>10&&[num2 integerValue]>15)?@"兩個都符合要求":@"都沒有答合要求"; }]; [reduceSignal subscribeNext:^(id x) { NSLog(@"reduce當前的值為:%@",x); }];
運行結果:
MobileProject[885:18784] concat拼接的值:10 2016-02-02 16:03:07.645 MobileProject[885:18784] concat拼接的值:20 2016-02-02 16:03:07.646 MobileProject[885:18784] then當前的值為:20 2016-02-02 16:03:07.646 MobileProject[885:18784] merge當前的值為:10 2016-02-02 16:03:07.646 MobileProject[885:18784] merge當前的值為:20 2016-02-02 16:03:07.647 MobileProject[885:18784] combineLastest當前的值為:<RACTuple: 0x7ff5ca606860> ( 10, 20 ) 2016-02-02 16:03:07.648 MobileProject[885:18784] zipWith當前的值為:<RACTuple: 0x7ff5ca60ab80> ( 10, 20 ) 2016-02-02 16:03:07.648 MobileProject[885:18784] zipWith中的RACTuple共有幾個值:2 2016-02-02 16:03:07.648 MobileProject[885:18784] zipWith中的RACTuple第一個值為:10 2016-02-02 16:03:07.648 MobileProject[885:18784] zipWith中的RACTuple最後一個值為:20 2016-02-02 16:03:07.649 MobileProject[885:18784] combineLastest結合reduct的第一個值為:10 第二個值為:20 2016-02-02 16:03:07.720 MobileProject[885:18784] reduce當前的值為:都沒有答合要求
1.3:其它一些操作:
//doNext: 執行Next之前,會先執行這個Block,可以做一些初使化的功能,doCompleted: 執行sendCompleted之前,會先執行這個Block [[[self.mySignal doNext:^(id x) { NSLog(@"doNext當前的值:%@",x); }] doCompleted:^{ NSLog(@"doComplete 執行到了"); }] subscribeNext:^(id x) { NSLog(@"測試doNext,doComplete的值:%@",x); }]; //switchToLatest:用於signalOfSignals(信號的信號),有時候信號也會發出信號,會在signalOfSignals中,獲取signalOfSignals發送的最新信號。 RACSubject *signalOfSignals = [RACSubject subject]; RACSubject *signal = [RACSubject subject]; // 獲取信號中信號最近發出信號,訂閱最近發出的信號。 // 註意switchToLatest:只能用於信號中的信號 [signalOfSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"switchToLatest%@",x); }]; [signalOfSignals sendNext:signal]; [signal sendNext:@1]; //deliverOn: 內容傳遞切換到制定線程中,副作用在原來線程中,把在創建信號時block中的代碼稱之為副作用。 //subscribeOn: 內容傳遞和副作用都會切換到制定線程中。' //timeout:超時,可以讓一個信號在一定的時間後,自動報錯。 [[self.mySignal timeout:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) { NSLog(@"timeout當前的值:%@",x); } error:^(NSError *error) { NSLog(@"timeout 超時了"); }]; //delay 延遲發送next。 [[self.mySignal delay:2] subscribeNext:^(id x) { NSLog(@"delay執行%@",x); }]; //retry重試 :只要失敗,就會重新執行創建信號中的block,直到成功. __block int i = 0; [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { if (i == 10) { [subscriber sendNext:@100]; }else{ NSLog(@"接收到錯誤"); [subscriber sendError:nil]; } i++; return nil; }] retry] subscribeNext:^(id x) { NSLog(@"retry當前的值:%@",x); } error:^(NSError *error) { }]; //普通執行多次訂閱 RACSignal *oneSignal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; return nil; }] replay]; [oneSignal subscribeNext:^(id x) { NSLog(@"第一個沒有replay執行的內容:%@",x); }]; [oneSignal subscribeNext:^(id x) { NSLog(@"第二個沒有replay執行的內容:%@",x); }]; //replay重放:當一個信號被多次訂閱,反覆播放內容 RACSignal *replaySignal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; return nil; }] replay]; [replaySignal subscribeNext:^(id x) { NSLog(@"replay第一個訂閱者%@",x); }]; [replaySignal subscribeNext:^(id x) { NSLog(@"replay第二個訂閱者%@",x); }]; //interval 定時:每隔一段時間發出信號 [[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) { NSLog(@"interval一直在執行:%@",x); }]; //throttle節流:當某個信號發送比較頻繁時,可以使用節流,在某一段時間不發送信號內容,過了一段時間獲取信號的最新內容發出。
運行結果:
2016-02-02 16:03:07.720 MobileProject[885:18784] doNext當前的值:10 2016-02-02 16:03:07.720 MobileProject[885:18784] 測試doNext,doComplete的值:10 2016-02-02 16:03:07.721 MobileProject[885:18784] doComplete 執行到了 2016-02-02 16:03:07.721 MobileProject[885:18784] switchToLatest1 2016-02-02 16:03:07.722 MobileProject[885:18784] timeout當前的值:10 2016-02-02 16:03:07.722 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.723 MobileProject[885:18784] 第一個沒有replay執行的內容:1 2016-02-02 16:03:07.723 MobileProject[885:18784] 第一個沒有replay執行的內容:2 2016-02-02 16:03:07.723 MobileProject[885:18784] 第二個沒有replay執行的內容:1 2016-02-02 16:03:07.723 MobileProject[885:18784] 第二個沒有replay執行的內容:2 2016-02-02 16:03:07.724 MobileProject[885:18784] replay第一個訂閱者1 2016-02-02 16:03:07.724 MobileProject[885:18784] replay第一個訂閱者2 2016-02-02 16:03:07.724 MobileProject[885:18784] replay第二個訂閱者1 2016-02-02 16:03:07.724 MobileProject[885:18784] replay第二個訂閱者2 2016-02-02 16:03:07.838 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.838 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.838 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.838 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.839 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.865 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.865 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.865 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.866 MobileProject[885:18784] 接收到錯誤 2016-02-02 16:03:07.866 MobileProject[885:18784] retry當前的值:100 2016-02-02 16:03:08.726 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:08 +0000 2016-02-02 16:03:09.724 MobileProject[885:18784] delay執行10 2016-02-02 16:03:09.725 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:09 +0000 2016-02-02 16:03:10.726 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:10 +0000 2016-02-02 16:03:11.724 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:11 +0000 2016-02-02 16:03:12.727 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:12 +0000 2016-02-02 16:03:13.725 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:13 +0000 2016-02-02 16:03:14.730 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:14 +0000 2016-02-02 16:03:15.726 MobileProject[885:18784] interval一直在執行:2016-02-02 08:03:15 +0000
二:關於RACCommand的一些知識
@interface TestRacViewController () @property(nonatomic,strong)UITextField *userNameText; @property(strong,nonatomic)NSString *username; @property(nonatomic,strong)UIButton *loginButton,*racCommendButton,*errCommendButton,*mainThreadButton,*netWorkButton,*testButton; @property(nonatomic,strong)RACCommand *otherMyRaccomand,*mainThreadCommend,*netWorkCommend,*testPropertyCommend; @end
//佈局 -(void)loadPage { if (!self.userNameText) { self.userNameText=[[UITextField alloc]init]; self.userNameText.backgroundColor=[UIColor whiteColor]; self.userNameText.placeholder=@"輸入用戶名"; [self.view addSubview:self.userNameText]; [self.userNameText mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.view.mas_left).with.offset(15); make.top.mas_equalTo(self.view.mas_top).with.offset(70); make.right.mas_equalTo(self.view.mas_right).with.offset(-15); make.height.mas_equalTo(@40); }]; } if(!self.loginButton) { self.loginButton=[[UIButton alloc]init]; [self.loginButton setTitle:@"響應" forState:UIControlStateNormal]; self.loginButton.backgroundColor=[UIColor blueColor]; [self.view addSubview:self.loginButton]; [self.loginButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.view.mas_left).with.offset(15); make.top.mas_equalTo(self.userNameText.mas_bottom).with.offset(20); make.right.mas_equalTo(self.view.mas_right).with.offset(-15); make.height.mas_equalTo(@40); }]; } if(!self.racCommendButton) { self.racCommendButton=[[UIButton alloc]init]; [self.racCommendButton setTitle:@"RacCommend測試" forState:UIControlStateNormal]; self.racCommendButton.backgroundColor=[UIColor blueColor]; [self.view addSubview:self.racCommendButton]; [self.racCommendButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.view.mas_left).with.offset(15); make.top.mas_equalTo(self.loginButton.mas_bottom).with.offset(20); make.right.mas_equalTo(self.view.mas_right).with.offset(-15); make.height.mas_equalTo(@40); }]; } if(!self.errCommendButton) { self.errCommendButton=[[UIButton alloc]init]; [self.errCommendButton setTitle:@"ERROR測試" forState:UIControlStateNormal]; self.errCommendButton.backgroundColor=[UIColor blueColor]; [self.view addSubview:self.errCommendButton]; [self.errCommendButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.view.mas_left).with.offset(15); make.top.mas_equalTo(self.racCommendButton.mas_bottom).with.offset(20); make.right.mas_equalTo(self.view.mas_right).with.offset(-15); make.height.mas_equalTo(@40); }]; } if(!self.mainThreadButton) { self.mainThreadButton=[[UIButton alloc]init]; [self.mainThreadButton setTitle:@"主線程上運行" forState:UIControlStateNormal]; self.mainThreadButton.backgroundColor=[UIColor blueColor]; [self.view addSubview:self.mainThreadButton]; [self.mainThreadButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.view.mas_left).with.offset(15); make.top.mas_equalTo(self.errCommendButton.mas_bottom).with.offset(20); make.right.mas_equalTo(self.view.mas_right).with.offset(-15); make.height.mas_equalTo(@40); }]; } if(!self.netWorkButton) { self.netWorkButton=[[UIButton alloc]init]; [self.netWorkButton setTitle:@"屬性測試" forState:UIControlStateNormal]; self.netWorkButton.backgroundColor=[UIColor blueColor]; [self.view addSubview:self.netWorkButton]; [self.netWorkButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.view.mas_left).with.offset(15); make.top.mas_equalTo(self.mainThreadButton.mas_bottom).with.offset(20); make.right.mas_equalTo(self.view.mas_right).with.offset(-15); make.height.mas_equalTo(@40); }]; } if(!self.testButton) { self.testButton=[[UIButton alloc]init]; [self.testButton setTitle:@"測試特性" forState:UIControlStateNormal]; self.testButton.backgroundColor=[UIColor blueColor]; [self.view addSubview:self.testButton]; [self.testButton mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.view.mas_left).with.offset(15); make.top.mas_equalTo(self.netWorkButton.mas_bottom).with.offset(20); make.right.mas_equalTo(self.view.mas_right).with.offset(-15); make.height.mas_equalTo(@40); }]; } }
一些定義
//創建一個信號代碼 -(RACSignal *)testSignal { RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) { NSLog(@"創建信號"); [subscriber sendNext:@"Hi 我是一個信號"]; [subscriber sendCompleted]; return nil; }]; return signal; } //創建一個命令響應 -(RACCommand *)testCommend { @weakify(self); RACCommand *myCommend=[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { RACSignal *authSignal=[RACSignal empty]; @strongify(self); authSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { //可以根據要求加條件進行判斷是否創建信號 if ([self.username isEqualToString:@"wjy"]) { NSLog(@"符合要求"); [subscriber sendNext:@"我完成的命令響應"]; [subscriber sendCompleted]; } else { //錯誤 [subscriber sendError:[NSError errorWithDomain:@"報錯了" code:1 userInfo:nil]]; } return nil; }]; //materialize是為了處理拿不到error的問題 return [authSignal materialize]; }]; return myCommend; } //創建屬性的RACCommand -(RACCommand *)otherMyRaccomand { if (!_otherMyRaccomand) { _otherMyRaccomand=[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { NSLog(@"執行到新的RACCommand"); RACSignal *otherSignal=[RACSignal empty]; otherSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { if ([self.username isEqualToString:@"wjy"]) { [subscriber sendNext:@"我肯定可以運行的"]; [subscriber sendCompleted]; } else { [subscriber sendError:[NSError errorWithDomain:@"報錯了" code:401 userInfo:nil]]; } return nil; }]; return otherSignal; }]; } return _otherMyRaccomand; } //創建主線程上運行 -(RACCommand *)mainThreadCommend { @weakify(self); if (!_mainThreadCommend) { _mainThreadCommend=[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { RACSignal *authSignal=[RACSignal empty]; @strongify(self); authSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { @strongify(self); //可以根據要求加條件進行判斷是否創建信號 if ([self.username isEqualToString:@"wjy"]) { [subscriber sendNext:@(YES)]; [subscriber sendCompleted]; } else { //錯誤 [subscriber sendError:[NSError errorWithDomain:@"報錯了" code:1 userInfo:nil]]; } return nil; }]; return authSignal; }]; } return _mainThreadCommend; } //特性測試 -(RACCommand *)testPropertyCommend { if (!_testPropertyCommend) { } return _testPropertyCommend; } -(RACSignal *)nettestSignal { RACSignal *authSignal=[RACSignal empty]; authSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { LogInApi *reg = [[LogInApi alloc] initWithUsername:self.username password:@"123456"]; [reg startWithCompletionBlockWithSuccess:^(YTKBaseRequest *request) { LoginModel *model=[[LoginModel alloc]initWithString:request.responseString error:nil]; [subscriber sendNext:model]; [subscriber sendCompleted]; } failure:^(YTKBaseRequest *request) { [subscriber sendError:[NSError errorWithDomain:@"報錯了" code:1 userInfo:nil]]; }]; return nil; }]; return authSignal; } -(RACSignal *)netSignal { RACSignal *authSignal=[RACSignal empty]; authSignal=[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"測試"]; [subscriber sendCompleted]; return nil; }]; return authSignal; } //RACSubject的運用 -(RACSubject *)testSubject { RACSubject *sub=[RACSubject subject]; [sub sendNext:@"我是RACSubject"]; return sub; }
運用的內容:
[self loadPage]; @weakify(self); //把左邊的屬性跟右邊信號signal的sendNext值綁定 distinctUntilChanged為了當值相同時不執行 RAC(self,username)=[self.userNameText.rac_textSignal distinctUntilChanged]; //監聽username是否有變化,有變化就會執行subscribeNext 這個屬性要支持KVO 可變數組就不可以 [RACObserve(self, username) subscribeNext:^(NSString *x) { NSLog(@"你當前輸入的值為:%@",x); }]; //UIAlertView跟RAC結合 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"" message:@"Alert" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil]; [[alertView rac_buttonClickedSignal] subscribeNext:^(NSNumber *indexNumber) { if ([indexNumber intValue] == 1) { NSLog(@"你點了確定"); } else { NSLog(@"你點了取消"); } }]; [alertView show]; //Button響應事件 [[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *x) { @strongify(self); [[self testSignal] subscribeNext:^(id x) { NSLog(@"當前執行值為:%@",x); }]; }]; //Button用命令式運行 switchToLatest處理信號中傳遞的參數為信號 self.racCommendButton.rac_command=[self testCommend]; //這個綁定要放在executionSignals執行前面 否則只會有一個執行完成會響應 [self.racCommendButton.rac_command.executing subscribeNext:^(id x) { if ([x boolValue]) { NSLog(@"rac_command正在執行中"); } else { NSLog(@"rac_command執行完成"); } }]; //dematerialize處理可以響應處理跟完成的內容 [self.racCommendButton.rac_command.executionSignals subscribeNext:^(RACSignal *execution) { [[[execution dematerialize] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) { NSLog(@"提示內容:%@",x); } error:^(NSError *error) { NSLog(@"racCommend出錯了"); }]; }]; //關於otherMyRaccomand的方式 self.errCommendButton.rac_command=self.otherMyRaccomand; [self.otherMyRaccomand.executionSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"完成了 %@",x); }]; //這邊要註意是在errors 裡面執行subscribeNext 不是執行subscribeError [self.otherMyRaccomand.errors subscribeNext:^(NSError *error) { NSLog(@"出錯了 %@",error); }]; //主線程上操作 self.mainThreadButton.rac_command=self.mainThreadCommend; [[[self.mainThreadCommend.executionSignals.switchToLatest map:^id(id value) { if ([value boolValue]) { return @"跳浪帥"; } else { return @"出太陽好麽"; } }] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSString *str) { UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"我是彈出窗" message:[NSString stringWithFormat:@"%@",str] delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil]; [alert show]; }]; //網路請求 //Button響應事件 [[self.netWorkButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { [[[self netSignal] flattenMap:^RACStream *(id value) { return [RACReturnSignal return:[NSString stringWithFormat:@"%@ 我已經被改變了成為另外一個信號",value]]; }] subscribeNext:^(id x) { NSLog(@"輸出的內容:%@",x); }]; }];
三:雙向綁定
RACChannelTerminal *channelA = RACChannelTo(self, valueA); RACChannelTerminal *channelB = RACChannelTo(self, valueB); [[channelA map:^id(NSString *value) { if ([value isEqualToString:@"西"]) { return @"東"; } return value; }] subscribe:channelB]; [[channelB map:^id(NSString *value) { if ([value isEqualToString:@"左"]) { return @"右"; } return value; }] subscribe:channelA]; [[RACObserve(self, valueA) filter:^BOOL(id value) { return value ? YES : NO; }] subscribeNext:^(NSString* x) { NSLog(@"你向%@", x); }]; [[RACObserve(self, valueB) filter:^BOOL(id value) { return value ? YES : NO; }] subscribeNext:^(NSString* x) { NSLog(@"他向%@", x); }]; self.valueA = @"西"; self.valueB = @"左";
2015-08-15 20:14:46.544 Test[2440:99901] 你向西 2015-08-15 20:14:46.544 Test[2440:99901] 他向東 2015-08-15 20:14:46.545 Test[2440:99901] 他向左 2015-08-15 20:14:46.545 Test[2440:99901] 你向右
一個關於左右列表相互影響滾動的雙向綁定實例:
RACChannelTerminal *leftChannel = RACChannelTo(self.leftTableView, contentOffset); RACChannelTerminal *rightChannel = RACChannelTo(self.rightTableView, contentOffset); [[rightChannel map:^id(NSValue *offset) { CGPoint point = offset.CGPointValue; point.y /= 10; return [NSValue valueWithCGPoint:point]; }] subscribe:leftChannel]; [[leftChannel map:^id(NSValue *offset) { CGPoint point = offset.CGPointValue; point.y *= 10; return [NSValue valueWithCGPoint:point]; }] subscribe:rightChannel];
一個輸入內容自動計算:
RACChannelTerminal *characterRemainingTerminal = RACChannelTo(_loginButton, titleLabel.text); [[self.userNameText.rac_textSignal map:^id(NSString *text) { return [@(100 - (NSInteger)text.length) stringValue]; }] subscribe:characterRemainingTerminal];
二個輸入框相互影響:
RACChannelTerminal *textField1Channel = [view.textField1 rac_newTextChannel]; RACChannelTerminal *textField2Channel = [view.textField2 rac_newTextChannel]; [textField1Channel subscribe:textField2Channel]; [textField2Channel subscribe:textField1Channel];
四:重點類的說明
1: streams streams代表任意的值,其值會隨著事件發⽣變化,由RACStream類表⽰。值可能⻢上可⽤,或者 在將來某⼀段時間可⽤,但必須按順序獲取,也就是說,在獲取到第⼀個值之前,是不可能獲取到 第⼆個值。 streams 是⼀個構造因果關係的結構(Monad), 要瞭解這個概念可以看這篇⽂章:http:// blog.csdn.net/ensoo/article/details/7506872。它可以實現在基本的初始值上進⾏複雜的操作運算 (filter,map,reducet等)。 streams不會被經常使⽤,⼤多情況下表現為signal和sequences,即Signal和Sequence是由stream 繼承。 2:Signals Signals由RACSignal類表⽰。 Signals⼀般表⽰將來被傳遞的數據。當信號接收到數據時,值就會通過signal被髮送出去,它推送 數據給訂閱者。⽤戶必須訂閱信號才能獲取到它的值。 Signals發送3種不同類型的事件給它的訂閱者: 1)next:next事件是stream提供了⼀個新值。⽽RACStream類的⽅法也只能在這個值上進⾏操作運 算。和cocoa的集合不同的是,它可以包含⼀個nil值。 2)error:error事件表⽰在信號完成之前發⽣了錯誤。這個事件包含了⼀個NSError類型的錯誤。這 個值不會在RACStream類⾥存儲。 3)completed事件:表⽰信號已經成功地完成了。這個值也不會在RACStream類⾥存儲。 3:Subscription subscriber(訂閱者)表⽰等待或者能夠等待信號發送事件的任意對象。在框架中使⽤ RACSubscriber 協議表⽰,也即任意實現了RACSubscriber協議的對象都可以是訂閱者。 可以通過調⽤ -subscribeNext:error:completed:⽅法來創建訂閱。RACStream 和 RACSignal類的⼤ 多操作也會⾃⼰創建訂閱。 訂閱會對Signals對象引⽤計數加1,當信號發送錯誤或者完成事件後,會⾃動被處理,不需要⽤戶 關⼼記憶體管理。當然,⽤戶也可以⼿動處理。 4: Subjects subject由RACSubject類表⽰,它是可以⼿動控制的信號。 subject可以想成是signal的變體,就像NSMutableArray相對於NSArray⼀樣。它們是⾮RAC的代碼 和RAC代碼之間的橋梁,因此,⾮常有⽤。 有些subject提供了額外的功能。特別地,RACReplaySubject⽤於緩存事件,將來有訂閱者時,可以 將緩存的數據發送給訂閱者,⽐如,當請求⼀個⺴絡時,伺服器數據已經返回,但其它的數據還沒 有準備好,這時,先要將⺴絡請求結果緩存,等其它數據準備好時,再訂閱,⽽不⾄於⺴絡請求數 據丟失。 5:Commands command由RACCommand 類表⽰,它創建並訂閱響應action的信號。 通常command是由UI觸發的,像⼀個按鈕被點擊時。當command被觸發時,控制項會⾃動被禁⽤。 6:Connections connection由RACMulticastConnection類表⽰。它是在任意數量的訂閱者之間共用訂閱。 預設情況下,信號沒有訂閱時,是冷信號,也即當有訂閱者被添加進來後,信號才會開始⼯作,也 即變為熱信號。 這也是期望的⾏為,對於每個訂閱,數據值都會被延遲重新計算。否則,如果信號有副作⽤或者任 務開銷很⼤時,可能就會產⽣問題。 conection通過RACSignal的publish或者multicast⽅法創建, ⼀旦連接,信號就變為熱信息,訂閱會 保持激活狀態直到所有的訂閱連接被取消。 7:Sequences sequence由RACSequence 類表⽰。 sequence是⼀種集合,類似於NSArray。和數組不同,為了改進性能,在sequence⾥的值會延遲計 算,也即,只有需要輸出值時,結果才會被計算。sequences和cocoa⾥的集合⼀樣,也不能包含nil 值。 對於⼤多數據的集合類,RAC添加了-rac_sequence ⽅法來⽣成RACSequence類進⾏操作。 8:Disposables RACDisposable 類⽤於取消訂閱或者清理資源。 Disposables⼤多情況下⽤於取消信號的訂閱 。 9:Schedulers scheduler由RACScheduler類表⽰,它是信號執⾏任務時所在的隊列(queue)或者信號執⾏完後將 結果放到隊列⾥執⾏,可以認為就是gcd⾥的queues。 scheduler⽀持取消操作,⽽且它總是串⾏地執⾏任務。這有利於避免死鎖。 RACScheduler有時候也類似NSOperationQueue,但它不允許任務間相互依賴。 10:Value types RAC提供了以下類⽤於表⽰各種值: 1)RACTuple: ⼀個⽐較少數量值,⼤⼩固定的,可以包含nil的集合。⼀般⽤於表⽰多個streams 的聚合值。 2)RACUnit :⼀個單例的空值,表⽰stream不包含有意義的值。 3)RACEvent : 代表任意的信號事件。 11:Asynchronous Backtraces 由於基於RAC的代碼經常和非同步相關,因此,為了更⽅便調試,RAC⽀持捕獲當前的asynchronous backtraces(非同步調⽤棧)。
五:副作用及消除副作用
__block int aNumber = 0; // Signal that will have the side effect of incrementing `aNumber` block // variable for each subscription before sending it. RACSignal *aSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) { aNumber++; [subscriber sendNext:@(aNumber)]; [subscriber sendCompleted]; return nil; }]; // This will print "subscriber one: 1" [aSignal subscribeNext:^(id x) { NSLog(@"subscriber one: %@", x); }]; // This will print "subscriber two: 2" [aSignal subscribeNext:^(id x) { NSLog(@"subscriber two: %@", x); }];
上面這樣就會產生副作用,第一個跟第二個的值會不一樣,被累加;採用RACMulticastConnection來消除
__block int aNumber = 0; // Signal that will have the side effect of incrementing `aNumber` block // variable for each subscription before sending it. RACSignal *aSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) { aNumber++; [subscriber sendNext:@(aNumber)]; [subscriber sendCompleted]; return nil; }]; RACMulticastConnection *connection = [aSignal multicast:[RACReplaySubject subject]]; [connection connect]; // This will print "subscriber one: 1" [connection.signal subscribeNext:^(id x) { NSLog(@"subscriber one: %@", x); }]; // This will print "subscriber two: 1" [connection.signal subscribeNext:^(id x) { NSLog(@"subscriber two: %@", x); }];
這樣兩次都只返回相同的內容,為1;其同要註意是調用connection.signal;下麵是官網的一個網路請求實例:
RACSignal *networkRequest = [RACSignal createSignal:^(id<RACSubscriber> subscriber) { AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { [subscriber sendError:error]; }]; [client enqueueHTTPRequestOperation:operation]; return [RACDisposable disposableWithBlock:^{ [operation cancel]; }]; }]; // Starts a single request, no matter how many subscriptions `connection.signal` // gets. This is equivalent to the -replay operator, or similar to // +startEagerlyWithScheduler:block:. RACMulticastConnection *connection = [networkRequest multicast:[RACReplaySubject subject]]; [connection connect]; [connection.signal subscribeNext:^(id response) { NSLog(@"subscriber one: %@", response); }]; [connection.signal subscribeNext:^(id response) { NSLog(@"subscriber two: %@", response); }];
這兩個訂閱者接收到了同樣的一個請求的內容。
六:工作原理
因為代碼中已經有相應的註解,所以文字說明就比較少,若有不明白可以留言;