使用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)
}