问题描述
我有一个需要发送到服务器的对象列表,我想一个接一个地执行此操作(不并行执行)。在所有对象均已发送且没有错误之后,我想运行其他功能不同的Observable。
let objects = [1,2,3]
let _ = Observable.from(objects).flatMap { object -> Observable<Void> in
return Observable.create { observer in
print("Starting request \(object)")
dispatchQueue.main.asyncAfter(deadline: .Now() + 2) { // one request takes ~2sec
print("Request \(object) finished")
observer.onNext(Void())
observer.onCompleted()
}
return disposables.create()
}
}.flatMap { result -> Observable<Void> in
print("Do something else (but only once)")
return Observable.just(Void())
}.subscribe(
onNext: {
print("Next")
},onCompleted: {
print("Done")
}
)
我得到的是
Starting request 1
Starting request 2
Starting request 3
Request 1 finished
Do something else (but only once)
Next
Request 2 finished
Do something else (but only once)
Next
Request 3 finished
Do something else (but only once)
Next
Done
整个过程在2秒后结束。我想要的是
Starting request 1
Request 1 finished
Starting request 2
Request 2 finished
Starting request 3
Request 3 finished
Do something else (but only once)
Next
Done
整个序列应在6秒后结束(因为它不是并行执行的)。
我将其与递归函数一起使用。但是,在有很多请求的情况下,这以深度递归堆栈结束,我想避免这种情况。
解决方法
使用concatMap
代替flatMap
,以便一次发送一次而不是一次发送。在此处了解更多信息:
RxSwift’s Many Faces of FlatMap
然后只做一次操作,请使用toArray()
。这是一个完整的示例:
let objects = [1,2,3]
_ = Observable.from(objects)
.concatMap { object -> Observable<Void> in
return Observable.just(())
.debug("Starting Request \(object)")
.delay(.seconds(2),scheduler: MainScheduler.instance)
.debug("Request \(object) finished")
}
.toArray()
.flatMap { results -> Single<Void> in
print("Do something else (but only once)")
return Single.just(())
}
.subscribe(
onSuccess: { print("done") },onError: { print("error",$0) }
)