MVVM模式在iOS中常用場(chǎng)景

使用MVVM模式可以讓Model--ViewModel--UI間形成綁定關(guān)系,Model數(shù)據(jù)變化可以通過VM直接更新UI;
在實(shí)際的場(chǎng)景,比如一些復(fù)雜的情況:

  • 多個(gè)異步請(qǐng)求,獲取到全部回調(diào)才更新UI
  • 依賴請(qǐng)求,第二個(gè)請(qǐng)求依賴于第一個(gè)請(qǐng)求結(jié)果
  • 失敗重試,需要自定義重試次數(shù)

那MVVM該如何設(shè)計(jì)呢?
核心業(yè)務(wù)邏輯還是交給ViewModel處理,暴露接口給外部調(diào)用,ViewController/View只做訂閱。使用RACSubject(ReactiveObjc)或PublishSubject(RxSwift)來(lái)發(fā)送數(shù)據(jù)。

一.Controller/View層的處理

OC

/// 綁定
- (void)bind {
    [self.viewModel.dataSubject subscribeNext:^(id  _Nullable x) {
        NSLog(@"直接獲取所有信息信息%@", x);
    }];
    [self.viewModel.moneySubject subscribeNext:^(id  _Nullable x) {
        NSLog(@"通過用戶信息獲取的錢包信息%@", x);
    }];
    [self.viewModel.orderListSubject subscribeNext:^(id  _Nullable x) {
        NSLog(@"獲取的訂單列表%@", x);
    }];
}

#pragma mark - 場(chǎng)景1:多個(gè)異步請(qǐng)求,全部處理完才回調(diào)到同一處去處理
- (void)mutiRequestSingleCompletion {
    [self.viewModel multiRequestSingleCompletion];
}

#pragma mark - 場(chǎng)景2:多個(gè)異步請(qǐng)求,有序,A請(qǐng)求完再繼續(xù)B請(qǐng)求(B依賴于A)
- (void)multiRequestDependsOnRequest {
    [self.viewModel multiRequestDependsOnRequest];
}

#pragma mark - 場(chǎng)景3:在失敗情況下重新請(qǐng)求的
- (void)requestMultiTimesWhenFailed {
    [self.viewModel requestMultiTimesWhenFailed];
}

Swift

    override func viewDidLoad() {
        super.viewDidLoad()
        self.bind()

        self.baseViewModel.multiRequestSingleCompletion()
        self.baseViewModel.multiRequestDependsOnRequest()
        self.baseViewModel.requestMultiTimesWhenFailed()
    }
    
    // MARK: -綁定
    func bind() {
        self.baseViewModel.dataSubject.subscribe { val in
            print(val.element!);
        }.disposed(by: disposeBag)
        
        self.baseViewModel.moneySubject.subscribe { val in
            print(val.element!);
        }.disposed(by: disposeBag)
        
        self.baseViewModel.orderListSubject.subscribe { val in
            print(val.element!);
        }.disposed(by: disposeBag)
    }
1.多個(gè)異步請(qǐng)求,全部處理完才回調(diào)到同一處去處理。

假設(shè)同時(shí)有以下請(qǐng)求:用戶信息、錢包信息、訂單信息;拿到全部回調(diào)后才會(huì)更新UI
OC

/// 獲取完用戶信息、錢包信息、訂單信息才會(huì)回調(diào)一次
- (void)multiRequestSingleCompletion {
    //  定義信號(hào)
    RACSubject *userProfileSubject = [RACSubject subject];
    RACSubject *walletSubject      = [RACSubject subject];
    RACSubject *orderSubject       = [RACSubject subject];
    //  組合
    @weakify(self);
    [[RACSignal combineLatest:@[userProfileSubject, walletSubject, orderSubject]]subscribeNext:^(RACTuple * _Nullable x) {
        @strongify(self);
        NSArray *array = [x allObjects];        
        [self.dataSubject sendNext:array];
    }];
    //  發(fā)送信號(hào)值,沒有對(duì)subject強(qiáng)引用,直接調(diào)用
    [self requestUserProfile:^(id  _Nonnull info) {
        [userProfileSubject sendNext:info];
    }];
        
    [self requestUserWallet:^(id  _Nonnull info) {
        [walletSubject sendNext:info];
    }];
        
    [self requestUserOrder:^(id  _Nonnull info) {
        [orderSubject sendNext:info];
    }];
}

Swift

/// 獲取完用戶信息、錢包信息、訂單信息才會(huì)回調(diào)一次
    func multiRequestSingleCompletion() {
        //  定義信號(hào)
        let userProfileSubject = PublishSubject<Any>()
        let walletSubject      = PublishSubject<Any>()
        let orderSubject       = PublishSubject<Any>()
        //  組合
        Observable.combineLatest([userProfileSubject, walletSubject, orderSubject]).subscribe { val in
            self.dataSubject.onNext(val.element!)
        }.disposed(by: disposeBag)
        
        // 發(fā)送
        self.requestUserProfile { info in
            userProfileSubject.onNext(info)
        }
        self.requestUserWallet { info in
            walletSubject.onNext(info)
        }
        self.requestUserOrder { info in
            orderSubject.onNext(info)
        }
    }
2.多個(gè)異步請(qǐng)求,有序,A請(qǐng)求完再繼續(xù)B請(qǐng)求(B依賴于A)

需要先獲取用戶信息,再通過用戶信息獲取錢包信息
OC

/// 獲取完用戶信息,再通過用戶信息獲取錢包
- (void)multiRequestDependsOnRequest {
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@{@"name":@"Tom"}];
        [subscriber sendCompleted];
        return nil;
    }];
        
    @weakify(self);
    signal = [signal flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
        NSLog(@"用戶%@", value);
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            @strongify(self);
            [self requestUserWallet:^(id  _Nonnull info) {
                [subscriber sendNext:@{@"money":@"100"}];
                [subscriber sendCompleted];
            }];
            return nil;
        }];
    }];
        
    [signal subscribeNext:^(id  _Nullable x) {
        @strongify(self);
        [self.moneySubject sendNext:x];
    }];    
}

Swift

/// 獲取完用戶信息,再通過用戶信息獲取錢包
    func multiRequestDependsOnRequest() {
        var observable = Observable<Any>.create { observer in
            observer.onNext(["name":"Tom"])
            return Disposables.create()
        }
        observable = observable.flatMap { val in
            return Observable<Any>.create { observer in
                self.requestUserWallet { val in
                    observer.onNext(["money":"100"])
                }
                return Disposables.create()
            }
        }
        observable.subscribe { val in
            self.moneySubject.onNext(val.element!)
        }.disposed(by: disposeBag)
    }
3.在失敗情況下重新請(qǐng)求

最多允許請(qǐng)求失敗的次數(shù)為retryTimes,超過retryTimes則停止任務(wù),發(fā)送錯(cuò)誤原因
OC

/// 請(qǐng)求失敗后重試
- (void)requestMultiTimesWhenFailed {
    @weakify(self);
    __block NSInteger failedTimes = 0;
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        @strongify(self);
        [self requestOrderList:^(BOOL status, id  _Nonnull info) {
            if (!status) {
                failedTimes ++;
                if (failedTimes <= self.retryTimes) {
                    NSLog(@"請(qǐng)求失敗次數(shù)%ld", failedTimes);
                    [subscriber sendError:nil];
                } else {
                    NSLog(@"請(qǐng)求失敗次數(shù)%ld,不再自動(dòng)請(qǐng)求", failedTimes);
                }
            } else {
                [subscriber sendNext:info];
            }
        }];
        return nil;
    }];
    
    RACSignal *retrySignal = [signal retry];
    [retrySignal subscribeNext:^(id  _Nullable x) {
        @strongify(self);
        [self.orderListSubject sendNext:x];
    }];
}

Swift

/// 請(qǐng)求失敗后重試,獲取訂單信息
    func requestMultiTimesWhenFailed() {
        Observable<Any>.create { observer in
            self.requestOrderList { status, val in
                if status == true {
                    observer.onNext(val)
                } else {
                    self.curFailedTimes += 1
                    if self.retrytimes < self.curFailedTimes {
                    } else {
                        print("失敗\(self.curFailedTimes)")
                        observer.onError(NSError(domain: "網(wǎng)絡(luò)異常", code: 502, userInfo: nil))
                    }
                }
            }
            return Disposables.create()
        }.retry(self.retrytimes).subscribe { val in
            self.orderListSubject.onNext(val)
        } onError: { error in
            print(error.localizedDescription);
        }.disposed(by: disposeBag)
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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