引用網絡上一些實例的代碼,針對ReactiveCocoa的運用可以更加有幫助;
1:跟AF結合時的寫法,返回RACSignal
- (RACSignal *)fetchQuestionWithTag:(NSString *)tag { NSString *relativeURL = [NSString stringWithFormat:@"http://api.stackexchange.com/2.1/questions/?site=stackoverflow&order=desc&sort=hot&tagged=%@", tag]; RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { AFHTTPRequestOperation *operation = [ [AFHTTPRequestOperationManager manager] GET:relativeURL parameters:nil success:^(AFHTTPRequestOperation *operation, NSDictionary *responSEObject) { [subscriber sendNext:responseObject[@"items"]]; [subscriber sendCompleted]; } failure:^(AFHTTPRequestOperation *operation, NSError *error){ [subscriber sendError:error]; }]; return [RACDisposable disposableWithBlock:^{ [operation cancel]; }]; }]; return signal; }
2:RACCommand的運用,作為事件響應
定義一個ViewModel@interface SubscribeViewModel : NSObject@property(nonatomic, strong) RACCommand *subscribeCommand;// write to this property@property(nonatomic, strong) NSString *email;// read from this property@property(nonatomic, strong) NSString *statusMessage;@end
@property(nonatomic, strong) RACSignal *emailValidSignal;實現代碼:- (RACCommand *)subscribeCommand { if (!_subscribeCommand) { @weakify(self); _subscribeCommand = [[RACCommand alloc] initWithEnabled:self.emailValidSignal signalBlock:^RACSignal *(id input) { @strongify(self); return [SubscribeViewModel postEmail:self.email]; }]; } return _subscribeCommand;}+ (RACSignal *)postEmail:(NSString *)email { AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.requestSerializer = [AFJSONRequestSerializer new]; NSDictionary *body = @{@"email": email ?: @""}; return [[[manager rac_POST:kSubscribeURL parameters:body] logError] replayLazily];}- (RACSignal *)emailValidSignal { if (!_emailValidSignal) { _emailValidSignal = [RACObserve(self, email) map:^id(NSString *email) { return @([email isValidEmail]); }]; } return _emailValidSignal;}
調用綁定:- (void)bindWithViewModel { RAC(self.viewModel, email) = self.emailTextField.rac_textSignal; self.subscribeButton.rac_command = self.viewModel.subscribeCommand; RAC(self.statusLabel, text) = RACObserve(self.viewModel, statusMessage);}- (UITextField *)emailTextField { if (!_emailTextField) { _emailTextField = [UITextField new]; _emailTextField.borderStyle = UITextBorderStyleRoundedRect; _emailTextField.font = [UIFont boldSystemFontOfSize:16]; _emailTextField.placeholder = NSLocalizedString(@"Email address", nil); _emailTextField.keyboardType = UIKeyboardTypeEmailAddress; _emailTextField.autocapitalizationType = UITextAutocapitalizationTypeNone; } return _emailTextField;}- (UIButton *)subscribeButton { if (!_subscribeButton) { _subscribeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [_subscribeButton setTitle:NSLocalizedString(@"Subscribe", nil) forState:UIControlStateNormal]; } return _subscribeButton;}- (UILabel *)statusLabel { if (!_statusLabel) { _statusLabel = [UILabel new]; } return _statusLabel;}
說明:RACCommand類用于表示事件的執行,一般來說是在UI上的某些動作來觸發這些事件,比如點擊一個按鈕。RACCommand的實例能夠決定是否可以被執行,這個特性能反應在UI上,而且它能確保在其不可用時不會被執行。通常,當一個命令可以執行時,會將它的屬性allowsConcurrentExecution設置為它的默認值:NO,從而確保在這個命令已經正在執行的時候,不會同時再執行新的操作。命令執行的返回值是一個RACSignal,因此我們能對該返回值進行next:,completed或error:,
3:關于RACObserve的用法
監聽對象的成員變量變化,當成員變量值被改變時,觸發做一些事情。 這種情況其實就是IOS KVO機制使用的場景,使用KVO實現,通常有三個步驟:1,給對象的成員變量添加監聽;2,實現監聽回調;3,取消監聽;而通過RAC可以直接實現,RAC的回調是通過block實現的,類似于過程式編程,上下文也更容易理解一些。
a: 場景:當前類有一個成員變量 NSString *input,當它的值被改變時,發送一個請求。
[RACObserve(self, input) subscribeNext:^(NSString* x){ request(x);//發送一個請求 }];
說明:每次input值被修改時,就會調用此block,并且把修改后的值做為參數傳進來。
b:場景:在上面場景中,當用戶輸入的值以2開頭時,才發請求.
[[RACObserve(self, input) filter:^(NSString* value){ if ([value hasprefix:@"2"]) { return YES; } else { return NO; } }] subscribeNext:^(NSString* x){ request(x);//發送一個請求 }];
c:上面場景是監聽自己的成員變量,如果想監聽UITextField輸入值變化,框架也做了封裝可以代替系統回調
[[self.priceInput.rac_textSignal filter:^(NSString *str) { if (str.integerValue > 20) { return YES; } else { return NO; } }] subscribeNext:^(NSString *str) { request(x);//發送一個請求 }];
d:場景:button監聽 兩個輸入框有值和一個成員變量值,當輸入框有輸入且成員變量為真時,button為可點擊狀態
RAC(self.payButton,enabled) = [RACSignal combineLatest:@[self.priceInput.rac_textSignal, self.nameInput.rac_textSignal, RACObserve(self, isConnected) ] reduce:^(NSString *price, NSString *name, NSNumber *connect){ return @(price.length > 0 && name.length > 0 && [connect boolValue]); }];
說明:同時監聽多個變量變化,當這些變量滿足一定條件時,使button為可點擊狀態
e:場景:滿足上面條件時,直接發送請求
[[RACSignal combineLatest:@[self.priceInput.rac_textSignal, self.nameInput.rac_textSignal, RACObserve(self, isConnected) ] reduce:^(NSString *price, NSString *name, NSNumber *connect){ return @(price.length > 0 && name.length > 0 && ![connect boolValue]); }] subscribeNext:^(NSNumber *res){ if ([res boolValue]) { NSLog(@"XXXXX send request"); } }];
f:distinctUntilChanged直到收到不同值才響應,可以過濾掉那些不必要的網絡請求等
@weakify(self); //Start Binding our properties RAC(self.nameField,text) = [RACObserve(self.viewModel, playerName) distinctUntilChanged]; [[self.nameField.rac_textSignal distinctUntilChanged] subscribeNext:^(NSString *x) { //this creates a reference to self that when used with @weakify(self); //makes sure self isn't retained @strongify(self); self.viewModel.playerName = x; }];
4:RACScheduler為RAC調度類(主線程,子線程等)
顯示網絡下載的圖片
RAC(self.imageView, image) = [[RACSignal startEagerlyWithScheduler:[RACScheduler schedulerWithPriority:RACSchedulerPriorityBackground] block:^(id <RACSubscriber> subscriber) { NSError *error; NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://ww3.sinaimg.cn/bmiddle/7128be06jw1ei4hfthoj3j20hs0bomyd.jpg"]options:NSDataReadingMappedAlwayserror:&error]; if(error) { [subscriber sendError:error];} else { [subscriber sendNext:[UIImage imageWithData:data]]; [subscriber sendCompleted];} }] deliverOn:[RACScheduler mainThreadScheduler]];
說明:這段代碼會在后臺線程立即發起一個請求,然后傳遞到主線程上更新UI,主線程上執行[RACScheduler mainThreadScheduler],信號傳遞:- (RACSignal *)deliverOn:(RACScheduler *)scheduler
5:控件結合的實例
a:對uibutton添加了一個rac_signalForControlEvents的方式,就不用利用addtarget的方式來再寫一個方法來進行對uibutton添加點擊事件了。
[[self.testBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { TestViewController *testVC = [[TestViewController alloc] init]; [self.navigationController pushViewController:testVC animated:YES];}];
b:在UIAlertView的使用
UIAlertView *chooseAlert = [[UIAlertView alloc] initWithTitle:@"選擇圖片上傳"message:nil delegate:nil cancelButtonTitle:@"取消"otherButtonTitles:@"拍照上傳", @"從相冊選擇", nil];[chooseAlert show];[[chooseAlert rac_buttonClickedSignal] subscribeNext:^(NSNumber *indexNumber) { if ([indexNumber intValue] == 1) { [self chooseFromCamera]; } else if ([indexNumber intValue] == 2) { [self chooseFromAlbum];}}];
c:在UITextfield的使用,self是因為我繼承了一個textfield先進行功能添加和封裝。所以self就是代指一個textfield了。
[[self rac_signalForControlEvents:UIControlEventEditingDidBegin] subscribeNext:^(NSNumber *editing) { self.bottomBorder.backgroundColor = [UIColor blackColor].CGColor;}];[[self rac_signalForControlEvents:UIControlEventEditingDidEnd] subscribeNext:^(NSNumber *editing) { self.bottomBorder.backgroundColor = [UIColor grayColor].CGColor;}];
說明:當選擇這個框的時候,線會加粗變黑
d:監控Uipagecontrol改變
[RACObserve(self.imagePlayer.pageControl, currentPage) subscribeNext:^(id x) { [self refreshSlideContent:self.imagePlayer.pageControl.currentPage];}];
新聞熱點
疑難解答