swift - RxSwift 异步任务

标签 swift rx-swift

我想通过点击登录按钮开始登录任务,完成后,获取用户订单列表、送货地址、愿望 list 和其他信息。 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)

关于swift - RxSwift 异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37475122/

相关文章:

ios - 观看操作系统 2.0 Beta : Not Receiving notifications

ios - 如何允许编辑由 RxDataSources 支持的 TableView ?

ios - 每次 UITextField 文本属性在 RxSwift 中更改时如何获得信号

ios - Rx swift : code working only first time

swift - RxSwift 如何更好地刷新 BehaviourSubject?

ios - 当使用 Parse 查询数据时,我的 View 仅在重复 while 之后加载

json - 使用 Swift 保存、检索和显示动态表数据

ios - 当在 vscode 上按 Swift 代码运行时,它会显示此错误 :

objective-c - iOS 8 + Swift 中的 setHTTPBody

ios - DisposeBag 内存泄漏?