ReactiveObjc初探

一. 存在的問題

  1. UI更新必須依賴程序員在指定位置手動(dòng)觸發(fā)。UI更新的邏輯會(huì)遍布各地難以維護(hù),而且調(diào)用者必須明確的知道更新的邏輯,因?yàn)閡pdatA,updateB,先調(diào)后調(diào)有時(shí)也會(huì)發(fā)生截然不同的效果。

  2. 舉個(gè)??,假如有一個(gè)類似網(wǎng)易云音樂的列表頁。歌曲列表請求成功后,賦值tabelView的數(shù)據(jù)源。注意,此時(shí)我們還有執(zhí)行[tableView reloadData],此外,可能還需要調(diào)更新歌曲數(shù),更新專輯封面等等。只要和這個(gè)數(shù)據(jù)源有關(guān)的UI元素,我們都需要手動(dòng)觸發(fā)一遍。更重要的是要更新哪些UI,需要我們自己判斷,極容易引發(fā)bug。上述是網(wǎng)絡(luò)請求的,在類似的多交互頁面中,常常還包括側(cè)滑刪除、批量增加、名稱修改等等對數(shù)據(jù)源的操作,而這些都意味著我們需要手動(dòng)觸發(fā)UI更新。當(dāng)然,有些共同的更新,我們可以抽成一個(gè)方法,但還是難以從根本上避免伴隨著用戶事件及數(shù)據(jù)改變的,散落各地的UI更新邏輯。

二. RAC的解決方案

  1. 還是上面那個(gè)場景,使用RAC后,只需要關(guān)心數(shù)據(jù)源如果變化,無需關(guān)心數(shù)據(jù)源變化后所引發(fā)的UI層面的連鎖反應(yīng)。加載更多,往數(shù)據(jù)源中加對應(yīng)數(shù)據(jù);刪除某首歌,刪除數(shù)據(jù)源中的對應(yīng)數(shù)據(jù)。修改數(shù)據(jù)后,訂閱(subscribe)了數(shù)據(jù)源的相關(guān)元素會(huì)自動(dòng)接收到數(shù)據(jù)變化的信號,并作出對應(yīng)改變。

  2. 光是上述效果我們用KVO也能做到,RAC更獨(dú)特的地方在于用信號量(Signal)統(tǒng)一了所有變化,包括網(wǎng)絡(luò)回調(diào)、KVO、通知、block等等,抽象成信號量后,我們可以統(tǒng)一進(jìn)行邏輯操作,包括combine、filter、map等等,這些操作才是強(qiáng)力的工具。整個(gè)流程為事件流->信號流->邏輯操作->訂閱。

三. 適合使用RAC的場景舉例

  1. 登錄注冊:登錄注冊常見的需求有必須同時(shí)滿足xxx條件,按鈕才能啟用。

@weakify(self);

    //自動(dòng)響應(yīng)登錄按鈕是否可用

    RAC(self.loginButton, enabled) = [RACSignal

                          combineLatest:@[self.accountTextField.rac_textSignal,

                                          self.pwdTextField.rac_textSignal]

                           reduce:^(NSString *userName,NSString *pwd){

                            return @(userName.length > 0 && pwd.length > 0);

                             }];

    //account屬性自動(dòng)響應(yīng)更新值

    [[self.accountTextField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {

        return value.length > 0;

    }] subscribeNext:^(NSString * _Nullable x) {

        @strongify(self);

        self.loginViewModel.account = x;

    }];

    //password屬性自動(dòng)響應(yīng)更新值

    [[self.pwdTextField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {

        return value.length > 0;

    }] subscribeNext:^(NSString * _Nullable x) {

        @strongify(self);

        self.loginViewModel.password = x;

    }];

    //按鈕點(diǎn)擊事件轉(zhuǎn)成信號流,調(diào)用VM中的方法執(zhí)行。

    [[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {

        @strongify(self);

        [[self.loginViewModel.loginCommand executing] subscribeNext:^(id  _Nullable x) {

            NSLog(@"登錄成功");

        }];

        [[self.loginViewModel.loginCommand execute:nil] subscribeError:^(NSError * _Nullable error) {

            NSLog(@"登錄失敗");

        }];

    }];



vm.m

- (void)setupCommand{ 
          @weakify(self); 
        _loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *                        _Nonnull(id _Nullable input) {
         return [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {

            @strongify(self);

            [self loginWithUserName:self.account password:self.password done:^(NSDictionary *result) {

                NSString *userId = [result objectForKey:@"user_id"];

                if (userId) {
                    [subscriber sendCompleted];
                }else{
                    [subscriber sendError:nil];
                }
            }];
            return nil;
        }];
    }];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容