ReactiveCocoa項目實戰(zhàn)例子

圖片發(fā)自簡書App

看完文檔后,似乎方法都知道怎么回事兒,但是應(yīng)用到項目上就無從下手,這篇文章就是來說一說項目實戰(zhàn)的例子。本文就綜合網(wǎng)上的文章和我平時遇到的問題來一一梳理一下,有一部分會是從其他地方引用而來,我會在文章下方說明出處。

實戰(zhàn)1:網(wǎng)絡(luò)下載圖片完成后 按鈕才可以點擊
-(void)btnAvliableWhenImgOK{
    //  觀察img 是否修改,如果修改就會觸發(fā)
    RACSignal * imagAvaibaleSignal = [RACObserve(self, self.imageView.image) map:^id(id value) {
        return  value ? @YES : @NO;
    }];    
    [imagAvaibaleSignal subscribeNext:^(id x) {
        NSLog(@"xx =%@",x);
    }];
    self.shareBtn.rac_command = [[RACCommand alloc] initWithEnabled:imagAvaibaleSignal signalBlock:^RACSignal *(id input) {
        // do share logic
        NSLog(@"input =%@",input);
        return [RACSignal empty];// 必須返回一個信號,不能返回nil
    }];
    // 一個command 需要execute 才能觸發(fā)執(zhí)行 但是和btn綁定的command不需要
     //  [self.shareBtn.rac_command execute:@"100"];
    /*
     2016-02-19 11:14:25.359 JFReactive[26455:2201124] xx =0
     2016-02-19 11:14:37.216 JFReactive[26455:2201124] xx =1
     2016-02-19 11:16:21.597 JFReactive[26455:2201124] input =<UIButton: 0x7f9d2bd6fc60; frame = (93 330; 151 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7f9d2bd6bcc0>>     */
}

我們使用RACObserver()觀察self.imgView.img,然后使用map操作如果有值則返回yes,否則返回no,接下來我們使用RACCommand 使用imgAvailableSigna作為參數(shù)初始化一個RACCommand并賦值給shareBtn.rac_command.
在運行上述代碼是img為nil 所以shareBtn enable = NO
在另外一個方法中下載圖片 使得 self.imgView.img = img, shareBtn的enable = yes

實現(xiàn)2: 使用rac_signalForSelector 實現(xiàn)協(xié)議方法

當(dāng)selector 執(zhí)行完后會發(fā)送next事件

 [[self rac_signalForSelector:@selector(scrollViewDidEndDecelerating:) fromProtocol:@protocol(UIScrollViewDelegate)] subscribeNext:^(RACTuple *tuple) {
        // do something
    }];
    
    [[self rac_signalForSelector:@selector(scrollViewDidScroll:) fromProtocol:@protocol(UIScrollViewDelegate)] subscribeNext:^(RACTuple *tuple) {
        // do something
    }];

實戰(zhàn)3: 網(wǎng)絡(luò)請求失敗后再發(fā)起一次請求

一般情況下,我們會遇到網(wǎng)絡(luò)請求失敗,但是失敗的原因有很多,總之我們還想再試一次,怎么辦呢?按照傳統(tǒng)的邏輯要定義一個標(biāo)簽,如果成功則返回該標(biāo)簽的值為yes,否則返回no,再次發(fā)起請求。好麻煩是不是,如果是RAC,就簡單了很多

-(void)retry{
   __block int flag = 0;
    
  RACSignal *signal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
      
       if (flag == 4){
        [subscriber sendNext:@"1"];
        [subscriber sendCompleted];
        }else{
            flag ++;
            NSLog(@"flag= %d",flag);
            [subscriber sendError:[NSError errorWithDomain:@"myerror " code:100 userInfo:nil]];
        }
      return nil;
    }];
    [[signal retry:5]subscribeNext:^(id x) {
        NSLog(@"xxxx =%@",x);
    }];
    
}

是不是很簡單,retry(count) 可以指定任意數(shù)字,直到我們獲取正確的結(jié)果或者到達(dá)指定的count次數(shù)

實戰(zhàn)4:發(fā)送請求發(fā)現(xiàn)lostToken了

例如在請求我的投資數(shù)據(jù)(reqInvestAPI)發(fā)現(xiàn)token過期了,傳統(tǒng)的做法是在發(fā)送請求之前先去請求token(reqTokenAPI),等token回來后再發(fā)reqInvestAPI,噢,LadyGaga,你好嗎?

  RACSignal *requestSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // suppose first time send request, access token is expired or invalid
        // and next time it is correct.
        // the block will be triggered twice.
        static BOOL isFirstTime = 0;
        NSString *url = @"http://httpbin.org/ip";
        if (!isFirstTime) {
            url = @"http://nonexists.com/error";
            isFirstTime = 1;
        }
        NSLog(@"url:%@", url);
        [[AFHTTPRequestOperationManager manager] GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
            [subscriber sendNext:responseObject];
            [subscriber sendCompleted];
            NSLog(@"subscriber sendcompleted");
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"subscriber send error");
            [subscriber sendError:error];
            
        }];
        return nil;
    }];
    
    self.labelForName.text = @"sending request...";
    //Subscribes to the returned signal when an error occurs.
    
    [[requestSignal catch:^RACSignal *(NSError *error) {// requestSignal 發(fā)送error 觸發(fā) catch{}  catch 中返回的signal 發(fā)送next 在subcribeNext接收后,再追加一次requestSignal
        self.labelForName.text = @"oops, invalid access token";
        NSLog(@"catch ....");
        // 模擬獲取token的請求,然后concat requestSignal,再次發(fā)送之前的請求
        return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            double delayInSeconds = 1.0;
            dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
            dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                [subscriber sendNext:@YES];
                NSLog(@"subscriber sendNext...");
                [subscriber sendCompleted];
            });
            return nil;
        }]concat:requestSignal];
    }] subscribeNext:^(id x) {
        NSLog(@"next =%@",x);
        if ([x isKindOfClass:[NSDictionary class]]) {
            self.labelForName.text = [NSString stringWithFormat:@"result:%@", x[@"origin"]];
        }
    } completed:^{
        NSLog(@"completed");
    }];
    

我們先創(chuàng)建了一個requestSignal,在這個signal中我們會先發(fā)送一次失敗的請求,然后被catch,catch方法中返回一個新的信號會被重新訂閱,在該信號中模擬網(wǎng)絡(luò)請求獲取token,然后再改請求token的signal中concat之前的信號(相當(dāng)于在此發(fā)送之前的請求)

實戰(zhàn)5:根據(jù)搜索框的文字進(jìn)行實時搜索

我們在用tmall 和 京東的app,會發(fā)現(xiàn)搜索框的結(jié)果會根據(jù)輸入的文字動態(tài)更新,這個放到我們的實際需求中會發(fā)現(xiàn),只要有用戶輸入的文字進(jìn)行改變我們就去發(fā)送請求,當(dāng)用戶前后兩次輸入間隔很短,我們發(fā)送了兩次請求,之前的請求還沒返回下一次的已經(jīng)發(fā)送了,這勢必會造成服務(wù)器的壓力,另外第一次的請求也要拋棄掉。如果放到RAC該如何處理呢?

[[[[[[self.textField.rac_textSignal throttle:1]distinctUntilChanged]ignore:@""] map:^id(id value) {
        NSLog(@"value =%@",value);
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            //  network request
            [subscriber sendNext:value];
            [subscriber sendCompleted];
            
            return [RACDisposable disposableWithBlock:^{
                
                //  cancel request
            }];
        }];
    }]switchToLatest] subscribeNext:^(id x) {// 如果不switchToLastest 則返回一個signal
        
        NSLog(@"x = %@",x);
    }];

我們在map中根據(jù)輸入框的值 模擬發(fā)送網(wǎng)絡(luò)請求。
throttle的參數(shù)是一個NSTimerInternal,指定一個時間間隔。
查看該方法的文檔知道,在interval間隔內(nèi)如果是已經(jīng)接收到下一個next 事件,就會拋棄前一個事件。
在這里我們設(shè)置間隔為1s,distinctchanged方法是檢測前后兩次事件的值是否改變,如果改變才會觸發(fā)接下來的事件

實戰(zhàn)6: 多個信號組合
 RACSignal * singal = [RACSignal
                          combineLatest:@[ RACObserve(self, self.model.age), RACObserve(self, self.model.name) ]
                          reduce:^(NSString *password, NSString *passwordConfirm) {
                              return @([passwordConfirm isEqualToString:password]);
                          }];
    [singal subscribeNext:^(id x) {
        NSLog(@"xx =%@",x) ;
    }];
    
    /* //  如果是直接RAC()的話 自動進(jìn)行了subscribeNext:
    RAC(self, self.textField.enabled) =[RACSignal
                                        combineLatest:@[ RACObserve(self, self.model.age), RACObserve(self, self.model.name) ]
                                        reduce:^(NSString *password, NSString *passwordConfirm) {
                                            return @([passwordConfirm isEqualToString:password]);
                                        }];
     */
實戰(zhàn)7:使用Command 模擬登錄
self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        //模擬login signal
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"1000"];
            [subscriber sendCompleted];
            return nil;
        }];
    }];
    // -executionSignals returns a signal that includes the signals returned from
    // the above block, one for each time the command is executed.
    [self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {
        // Log a message whenever we log in successfully.
        [loginSignal subscribeNext:^(id x) {
            NSLog(@"xxx  %@",x);
        }];
        [loginSignal subscribeCompleted:^{
            NSLog(@"Logged in successfully!");
        }];
    }];
//    [self.loginCommand.executionSignals.switchToLatest subscribeNext:^(id x) {
//        NSLog(@"xx =%@",x);
//    }];
    // Executes the login command when the button is pressed. 按鈕點擊觸發(fā)
    self.shareBtn.rac_command = self.loginCommand;

后續(xù)的再補(bǔ)充吧...

參考:
http://www.lxweimin.com/p/e10e5ca413b7

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內(nèi)容