我想通过点击登录按钮开始登录任务,完成后,获取用户订单列表,送货地址,愿望清单,其他信息. startTask是一个按钮,用户点击它,我将启动这些任务,但是现在如果登录任务失败,用户再次点
startTask是一个按钮,用户点击它,我将启动这些任务,但是现在如果登录任务失败,用户再次点击startTask按钮,我再也无法启动这些任务,为什么?
示例代码
private func test() { let data = ["fetch order list", "fetch shipping addresses", "fetch wishlist", "fetch other info"] let fetchInfoTasks = data.map{ asyncTask($0) }.toObservable() let someTasks = fetchInfoTasks.merge().toArray() let result = login().flatMapLatest{ _ in someTasks } startTask .rx_tap .flatMapLatest{ result } .catchError{ error in .....error...... return Observable.empty() } .subscribeNext{ tasks in .....all completed.... } .addDisposableTo(disposeBag) } private func login()-> Observable<String> { return Observable.create{ observer in performClosure(afterDealy: 1, onMainQueue: false) { if arc4random() % 4 == 0 { observer.onNext("login finished") observer.onCompleted() } else { observer.onError(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "some error"])) } } return AnonymousDisposable{} } } private func asyncTask(name: String)-> Observable<String> { return Observable.create{ observer in let delay = Double(arc4random() % 6 + 1) performClosure(afterDealy: delay, onMainQueue: false) { observer.onNext(name) observer.onCompleted() } return AnonymousDisposable{} } } func performClosure(afterDealy delay: Double, onMainQueue mainQueueOrNot: Bool, action: dispatch_block_t) { let delayIntervals = Double(NSEC_PER_SEC) * delay let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delayIntervals)) let queue = mainQueueOrNot ? dispatch_get_main_queue() : dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) dispatch_after(time, queue, action) }一旦发生错误,流终止.您不希望在按钮级别发生这种情况,因此您必须在更深层次上捕获错误.
例如:
startTask .rx_tap .flatMapLatest{ result .catchError{ error in .....error...... return Observable.empty() } } .subscribeNext{ tasks in .....all completed.... } .addDisposableTo(disposeBag)
这样,您可以防止实际的Rx错误通过flatMap冒泡.
如果您需要在出错时执行某些操作,您可能希望将结果包装在某种结果枚举中(建议使用https://github.com/antitypical/Result).
一个例子是:
startTask .rx_tap .flatMapLatest{ result .map { Result.Success(result: $0) .catchError{ error in return Result.Error(error: $0) } } .subscribeNext{ result in switch(result) { case .Success(let result): //display happy case case .Error(let error): //display sad case } .addDisposableTo(disposeBag)