Reactive Cocoa實踐舉例

這篇文章主要經過舉例說明Reactive Cocoa的使用方法,所舉的例子都比較典型和實用,在實際的項目中都會有所涉及,也但願你們能夠觸類旁通。服務器

 

 

一.輸入框輸入11位合法手機號,獲取驗證碼按鈕纔可用,號碼不合法,按鈕不可用,點擊按鈕,倒計時60s後,才能夠再次可用,在等待期間,不管輸入框輸入的是否再次合法,獲取驗證碼按鈕都是不可用的。函數

 

RACSignal *validPhone = [self.phoneTextField.rac_textSignal map:^id(NSString *text) {post

        return @([RegFun checkPhoneLegal:text]);this

}];spa

 

self.sendCodeBtn.rac_command = [[RACCommand alloc] initWithEnabled: validPhone signalBlock:^RACSignal *(id input) {orm

        return [self sendCodeSingal];server

}];  // validPhone控制點擊的block是否能夠執行,同時也控制了按鈕的狀態,當點擊後,只要block返回的signal尚未sendCompleted,這時候你不管怎麼輸入字符仍是作什麼操做,按鈕都是不可用的,這樣就解決了,正在請求接口,再輸入字符,按鈕又變成可用的問題。接口

 

-(RACSignal *)sendCodeSingal{圖片

return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {get

        [[AuthorizeURL sharedInstance] startWithM:URL_M_User andWithA:@"sendSmsCode" andOtherDic:dic andIsNeedWaitingView:YES andIsNeedPopMessageWhenSuccess:YES andIsNeedCallBlockWhenNoNetwork:YES andSuccessBlock:^(id responseObj, BOOL isSuccess) {

            if (isSuccess) {

                self.leftTime = 60;

                RACSignal *sendCodeEnableSignal = [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] take:self.leftTime]; //1s執行一次

                [sendCodeEnableSignal subscribeNext:^(id x) {

                    self.leftTime --;

                    [self.sendCodeBtn setTitle:[NSString stringWithFormat:@"等待(%d)",self.leftTime] forState:UIControlStateDisabled];

                    if (self.leftTime == 0) {  //時間爲0時,才發送信號,讓按鈕可用。

                        [self.sendCodeBtn setTitle:@"發送驗證碼" forState:UIControlStateDisabled];  //字符歸位,否則下次就會顯示等待0.

                        [subscriber sendNext:@(isSuccess)];

                        [subscriber sendCompleted];

                    }

                }];

            }else{

                [subscriber sendNext:@(isSuccess)];

                [subscriber sendCompleted];

            }

        }];

       

        return nil;

    }];

}

 

 

二.經過代碼直接textView.text = @」this is a example」,也要達到rac_textSignal同樣的信號效果。

 

//直接給值的話,rac_textSignal是不調用的,必須經過觀察,而後,輸入的時候,觀察是不調用的,二者合併,有一者觸發便可。

 

RACSignal *validUserName = [[RACSignal merge:@[self.userNameTextField.rac_textSignal, RACObserve(self.userNameTextField, text)]] map:^id(NSString *text) {

        return @(text.length > 0);

}];

 

 

三.很是解耦的控制底部tabbar小紅點和各個子小紅點的顯示和隱藏。

 

RACSignal *myMessageSignal =  RACObserve(self, myMessageCircleNum);

RACSignal *groupMessageSignal = RACObserve(self, groupMessageNum);

RACSignal *mySysMessageSignal = RACObserve(self, mySysMessageCircleNum);

//這三個數值控制三個子小紅點的顯示隱藏,監聽他們值的改變,有改變,就發通知,去刷頁面,去控制子小紅點的顯示和隱藏。

 

[groupMessageSignal subscribeNext:^(NSNumber *x) {

        [[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_CircleType object:@(8)]; //發送通知,其餘頁面只要有監聽,就能夠刷新頁面,和控制子其對應的子小紅點的顯示和隱藏。

        [self saveToLocalWithType:8];  //存本地

}];

 

RACSignal *helloCircleSignal = [RACSignal combineLatest:@[myMessageSignal,mySysMessageSignal,groupMessageSignal] reduce:^id(NSNumber *myMessage,NSNumber *mySysMessage,NSNumber *groupMessage){

    return @(myMessage.intValue == 0 && mySysMessage.intValue == 0 && groupMessage.intValue == 0);  //當三者都爲0,證實他們對應的子小紅點都隱藏了,那麼底部的小紅點也才消失。

}];

   

[helloCircleSignal subscribeNext:^(NSNumber *x) {

   XAppDelegate.homeVC.helloVCRedCircle.hidden = x.boolValue;

}];  //三者只要有一者的值改變,就會觸發這個合併的信號,就能夠刷新底部小紅點的顯示。



四.監聽登錄狀態的改變,從登錄到登出,從登出到登錄,狀態的改變須要刷新頁面和處理數據

 

//在登錄和登出的地方,會發出對應的通知,各個頁面只要監聽便可。

    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:KNOTIFICATION_USERLOGINCHANGE object:nil] subscribeNext:^(NSNotification *notification) {

        BOOL isinLogin = [notification.object boolValue];

        if (isinLogin) { //從未登陸到登陸。

            [self handleWhenLoginIn];

        }else{  //從登陸到未登陸。

            [self handleWhenLogout];

        }

    }];

 

 

五.替代各類delegate,讓代碼更集中,更易讀

 

UIActionSheet* sheet = [[UIActionSheet alloc]initWithTitle:nil delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"拍照",@"從相冊中選取", nil];

    [[sheet rac_buttonClickedSignal] subscribeNext:^(NSNumber* number) {   // UIActionSheetdelegate

        UIImagePickerController* controller = nil;

        int num = number.intValue;

        if(num == 0) { //拍照

            controller = [CameraAndPhoto getCameraPickerControllerAndIsFront:YES];

        }

        if(num == 1) { //相冊

            controller = [CameraAndPhoto getPhotoLibarayPickerController];

        }

        if ((num == 0 || num == 1) && controller) {

            [self presentViewController:controller animated:YES completion:nil];

            [[controller rac_imageSelectedSignal] subscribeNext:^(NSDictionary *info) {

                           // UIImagePickerController點擊肯定後調用

                [controller dismissViewControllerAnimated:YES completion:^{

                    UIImage *portraitImg = [info objectForKey:@"UIImagePickerControllerOriginalImage"];

                    VPImageCropperViewController *imgCropperVC = [[VPImageCropperViewController alloc] initWithImage:portraitImg cropFrame:CGRectMake(0, (kScreen_Height - kScreen_Width)/2, kScreen_Width,kScreen_Width) limitScaleRatio:4.0 andIsNeedCircle:YES];

 

                    imgCropperVC.delegate = self;  //delegate仍是要賦值的。

 

                    [[self rac_signalForSelector:@selector(imageCropper:didFinished:) fromProtocol:@protocol(VPImageCropperDelegate)] subscribeNext:^(RACTuple *tuple) {  //圖片裁切VCdelegate,原本是要散落在self頁面,如今集成到這裏,圖片裁切肯定後的回調

                        [imgCropperVC dismissViewControllerAnimated:YES completion:^{

                            UIImage *editedImage = tuple.second;

                           }];

}];

                    [[self rac_signalForSelector:@selector(imageCropperDidCancel:) fromProtocol:@protocol(VPImageCropperDelegate)] subscribeNext:^(RACTuple *tuple){  //圖片裁切VCdelegate,圖片裁切取消後的回調

                        [imgCropperVC dismissViewControllerAnimated:YES completion:^{

                        }];

                    }];

                    [self presentViewController:imgCropperVC animated:YES completion:nil];

                }];

            } completed:^{  // UIImagePickerController點擊取消後調用

                [controller dismissViewControllerAnimated:YES completion:^(){   //至關於cancel

                }];

            }];

        }

    }];

[sheet showInView:self.view];

 

 

六.信號混合使用,RACSubject的使用,將非RAC帶入RAC

 

self.textSingal = [RACSubject subject];  //先聲明

self.publishBtn.rac_command = [[RACCommand alloc] initWithEnabled:self.textSingal signalBlock:^RACSignal *(id input) {

        if (self.imageHasUploadToUpYun) {

            return [self tellServerSignalWith:nil];  //圖片已經上傳成功了,若是告訴咱們的服務器失敗了,第二次點擊按鈕的時候,不用從新上傳圖片,直接將地址告訴咱們的服務器。

        }else{

            return [self submitSignal];  //開始上傳圖片

        }

}];

[self.textSingal sendNext:[self isValid]]; //[self isValid]函數返回的NSNumber的值就是經過非RAC的普通代碼計算得來,來控制publishBtnenable狀態,這句話能夠放在其餘須要控制按鈕狀態的地方,好比選擇圖片後,調用一下,初始化的使用調用一下。

 

//代碼的例子是先把圖片上傳到雲服務器,上傳成功後,再將取得的圖片地址告訴本身的服務器。

-(RACSignal *)submitSignal{

    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

           self.uploadImageManager = [[UploadImageManager alloc] initWithMultiImageArray:self.multiPhotoVCManager.lastUploadImageArray andNeedWait:YES andMultiPhotoVCManager:self.multiPhotoVCManager andSuccessBlock:^(BOOL isAllComplete, NSArray *imageSrcArray, NSArray *hasSuccessObjArray, NSArray *hasFailedObjArray) {

               if (imageSrcArray.count > 0) {  //開始告訴咱們本身的服務器。

              self.imageHasUploadToUpYun = YES;  //這個時候,已經到雲了。除非再動圖片了,不然若是接下去告訴咱們本身的服務器失敗後,也不用再從新上傳圖片。

               RACSignal *temp = [self tellServerSignalWith:subscriber];  //此時信號爲冷的,將上傳到雲的信號的subscriber傳遞到告訴服務器的函數,這樣才能在告訴服務器的信號完成後,也讓上傳到雲的信號可以完成,造成迴路。

               [temp subscribeNext:^(id x) {  //調用一下,激活告訴服務器的信號。

               }];

          }else{  //上傳完成了,一張都沒有成功。

               [subscriber sendNext:@(0)];

               [subscriber sendCompleted];

          }

        return nil;

    }];

}

 

 

//將圖片地址告訴咱們本身的服務器

-(RACSignal *)tellServerSignalWith:(id<RACSubscriber>)subscriber1{

      return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

        [[AuthorizeURL sharedInstance] startWithM:URL_M_Daily andWithA:@"add" andOtherDic:dict andIsNeedWaitingView:YES andIsNeedPopMessageWhenSuccess:YES andIsNeedCallBlockWhenNoNetwork:YES andSuccessBlock:^(id responseObj, BOOL isSuccess) {

           [subscriber sendNext:@(isSuccess)];   //讓告訴咱們服務器圖片地址的信號結束

           [subscriber sendCompleted];

           [subscriber1 sendNext:@(isSuccess)];  //讓雲服務器的信號結束

           [subscriber1 sendCompleted];

        }];

        return nil;

}];

}

相關文章
相關標籤/搜索