我必须使用三个单独的API请求来获取三种类型的数据(AType
,BType
,CType
)。 API返回的对象由一对多关联:
AType
对象是N BType
个对象BType
对象是P CType
个对象的父对象)我使用以下三个函数来获取每种类型:
func get_A_objects() -> Observable<AType> { /* code here */ }
func get_B_objects(a_parentid:Int) -> Observable<BType> { /* code here */}
func get_C_objects(b_parentid:Int) -> Observable<CType> { /* code here */}
并且为了避免嵌套订阅,使用flatMap
链接这三个函数:
func getAll() -> Observable<CType> {
return self.get_A_objects()
.flatMap { (aa:AType) in return get_B_objects(aa.id) }
.flatMap { (bb:BType) in return get_C_objects(bb.id) }
}
func setup() {
self.getAll().subscribeNext { _ in
print ("One more item fetched")
}
}
上面的代码工作正常,当有AType
的M个对象时,我可以看到文本"One more item fetched"
打印了MxNxP次。
我想设置getAll()
功能,使用ReplaySubject<String>
在整个链中提供的状态更新。我最初的想法是写下这样的东西:
func getAll() -> ReplaySubject<String> {
let msg = ReplaySubject<String>.createUnbounded()
self.get_A_objects().doOnNext { aobj in msg.onNext ("Fetching A \(aobj)") }
.flatMap { (aa:AType) in
return get_B_objects(aa.id).doOnNext { bobj in msg.onNext ("Fetching B \(bobj)") }
}
.flatMap { (bb:BType) in
return get_C_objects(bb.id).doOnNext { cobj in msg.onNext ("Fetching C \(cobj)") }
}
return msg
}
但此尝试失败,即以下print()
不会打印任何内容。
getAll().subscribeNext {
print ($0)
}
我该如何重写逻辑?
答案 0 :(得分:1)
这是因为你没有保留你的Disposable
,因此他们会立即被解除分配,因此什么都不做。
在getAll
中,您可以通过Observable<AType>
创建get_A_objects()
,但不会将其添加到DisposeBag
。当它超出范围时(在func
的末尾),它将被取消分配。所以{ aobj in msg.onNext ("Fetching A \(aobj)") }
永远不会发生(或者至少不太可能,如果它是异步的)。
此外,您不会保留ReplaySubject<String>
返回的getAll().subscribeNext
。因此,出于同样的原因,这也将是一个交易破坏者。
由于您需要两个Observable
:一个用于实际的最终结果(Observable<CType>
),另一个用于进度状态(ReplaySubject<String>
),您应该从{{{ 1}}函数,这样两者都可以“拥有”,并且可以管理它们的生命周期。
getAll()
一些注意事项:
func getAll() -> (Observable<CType>, ReplaySubject<String>) {
let progress = ReplaySubject<String>.createUnbounded()
let results = self.get_A_objects()......
return (results, progress)
}
let (results, progress) = getAll()
progress
.subscribeNext {
print ($0)
}
.addDisposableTo(disposeBag)
results
.subscribeNext {
print ($0)
}
.addDisposableTo(disposeBag)
,如果您不小心可能会有危险。createUnbounded
,因为如果有人在之后订阅并且获得旧的进度状态消息,那么你以后会“抓取”某些内容将会是一个谎言。考虑使用ReplaySubject
。PublishSubject
之前订阅progress
以确保您不会错过任何进度状态消息,因为输出已赢得不再缓冲了。