美文网首页
MVVM模式在iOS中常用场景

MVVM模式在iOS中常用场景

作者: 麦子maizi | 来源:发表于2022-01-11 15:48 被阅读0次

    使用MVVM模式可以让Model--ViewModel--UI间形成绑定关系,Model数据变化可以通过VM直接更新UI;
    在实际的场景,比如一些复杂的情况:

    • 多个异步请求,获取到全部回调才更新UI
    • 依赖请求,第二个请求依赖于第一个请求结果
    • 失败重试,需要自定义重试次数

    那MVVM该如何设计呢?
    核心业务逻辑还是交给ViewModel处理,暴露接口给外部调用,ViewController/View只做订阅。使用RACSubject(ReactiveObjc)或PublishSubject(RxSwift)来发送数据。

    一.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 - 场景1:多个异步请求,全部处理完才回调到同一处去处理
    - (void)mutiRequestSingleCompletion {
        [self.viewModel multiRequestSingleCompletion];
    }
    
    #pragma mark - 场景2:多个异步请求,有序,A请求完再继续B请求(B依赖于A)
    - (void)multiRequestDependsOnRequest {
        [self.viewModel multiRequestDependsOnRequest];
    }
    
    #pragma mark - 场景3:在失败情况下重新请求的
    - (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.多个异步请求,全部处理完才回调到同一处去处理。

    假设同时有以下请求:用户信息、钱包信息、订单信息;拿到全部回调后才会更新UI
    OC

    /// 获取完用户信息、钱包信息、订单信息才会回调一次
    - (void)multiRequestSingleCompletion {
        //  定义信号
        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];
        }];
        //  发送信号值,没有对subject强引用,直接调用
        [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

    /// 获取完用户信息、钱包信息、订单信息才会回调一次
        func multiRequestSingleCompletion() {
            //  定义信号
            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)
            
            // 发送
            self.requestUserProfile { info in
                userProfileSubject.onNext(info)
            }
            self.requestUserWallet { info in
                walletSubject.onNext(info)
            }
            self.requestUserOrder { info in
                orderSubject.onNext(info)
            }
        }
    
    2.多个异步请求,有序,A请求完再继续B请求(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.在失败情况下重新请求

    最多允许请求失败的次数为retryTimes,超过retryTimes则停止任务,发送错误原因
    OC

    /// 请求失败后重试
    - (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(@"请求失败次数%ld", failedTimes);
                        [subscriber sendError:nil];
                    } else {
                        NSLog(@"请求失败次数%ld,不再自动请求", failedTimes);
                    }
                } else {
                    [subscriber sendNext:info];
                }
            }];
            return nil;
        }];
        
        RACSignal *retrySignal = [signal retry];
        [retrySignal subscribeNext:^(id  _Nullable x) {
            @strongify(self);
            [self.orderListSubject sendNext:x];
        }];
    }
    

    Swift

    /// 请求失败后重试,获取订单信息
        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: "网络异常", 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)
        }
    

    相关文章

      网友评论

          本文标题:MVVM模式在iOS中常用场景

          本文链接:https://www.haomeiwen.com/subject/dkpcqrtx.html