ReactiveCocoa是響應式編程(FRP)在iOS中的一個實現框架,它的開源地址爲:https://github.com/ReactiveCocoa/ReactiveCocoa# ;在網上看了幾篇文章,感受理論講了不少,可是代碼仍是看不太懂,因而本身把它github文檔上的一些使用的經典示例實現了一下,項目中有須要時能夠直接搬過去用,用的熟練了再讀源碼也比較容易理解。ios
例1. 監聽對象的成員變量變化,當成員變量值被改變時,觸發作一些事情。git
這種狀況其實就是IOS KVO機制使用的場景,使用KVO實現,一般有三個步驟:1,給對象的成員變量添加監聽;2,實現監聽回調;3,取消監聽;而經過RAC能夠直接實現,RAC的回調是經過block實現的,相似於過程式編程,上下文也更容易理解一些。github
場景:當前類有一個成員變量 NSString *input,當它的值被改變時,發送一個請求。編程
實現: xcode
- [RACObserve(self, input)
- subscribeNext:^(NSString* x){
- request(x);
- }];
每次input值被修改時,就會調用此block,而且把修改後的值作爲參數傳進來。app
場景:在上面場景中,當用戶輸入的值以2開頭時,才發請求.框架
實現:oop
- [[RACObserve(self, input)
- filter:^(NSString* value){
- if ([value hasPrefix:@"2"]) {
- return YES;
- } else {
- return NO;
- }
- }]
- subscribeNext:^(NSString* x){
- request(x);
- }];
場景:上面場景是監聽本身的成員變量,若是想監聽UITextField輸入值變化,框架也作了封裝能夠代替系統回調spa
實現:.net
- [[self.priceInput.rac_textSignal
- filter:^(NSString *str) {
- if (str.integerValue > 20) {
- return YES;
- } else {
- return NO;
- }
- }]
- subscribeNext:^(NSString *str) {
- <span style="white-space:pre"> </span>request(x);
}];
例2. 同時監聽多個變量變化,當這些變量知足必定條件時,使button爲可點擊狀態
場景: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]);
- }];
場景:知足上面條件時,直接發送請求
實現:
- [[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");
- }
- }];
例3. 相似於生成產-消費
場景:用戶每次在TextField中輸入一個字符,1秒內沒有其它輸入時,去發一個請求。TextField中字符改變觸發事件已在例1中展現,這裏實現一下它觸法的方法,把1秒延時在此方法中實現。
實現:
- - (void)showLoading {
-
- [self.loadingDispose dispose];
- @weakify(self);
- self.loadingDispose = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
- [subscriber sendCompleted];
- return nil;
- }] delay:1]
- subscribeCompleted:^{
- @strongify(self);
- doRequest();
- self.loadingDispose = nil;
- }];
- }
上面代碼看起來挻費解,不過下面一段相似的代碼拆開寫的,會比較容易理解:
- [self.loadingDispose dispose];
-
- RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
- subscriptions++;
- [subscriber sendNext:@"mytest"];
- [subscriber sendCompleted];
- return nil;
- }];
-
- loggingSignal = [loggingSignal delay:10];
-
- self.loadingDispose = [loggingSignal subscribeNext:^(NSString* x){
- NSLog(@"%@",x);
- NSLog(@"subscription %u", subscriptions);
- }];
-
- self.loadingDispose = [loggingSignal subscribeCompleted:^{
- NSLog(@"subscription %u", subscriptions);
- }];
loggingSignal在每次被調用subscriibeNext:^(id x)或subscribeCompleted:^方法時(12行和17行),它建立進傳進的參數block_1就會被觸動發,而block_1中的sendNext:方法會調用subscriibeNext:^中對應的block_2, 而block_1中的sendCompleted會調用subscribeCompleted:中對應的block_3