RxSwift:为啥 flatMapLatest 从不执行 onCompleted()?

Posted

技术标签:

【中文标题】RxSwift:为啥 flatMapLatest 从不执行 onCompleted()?【英文标题】:RxSwift: Why does flatMapLatest never execute onCompleted()?RxSwift:为什么 flatMapLatest 从不执行 onCompleted()? 【发布时间】:2018-08-09 18:48:07 【问题描述】:

在我的 Swift UIViewController 中,我尝试订阅变量类型的类成员,通过 flatMapLatest 调用运行它,然后在所有订阅者上执行 flatMapLatest 可观察对象中的 onCompleted() 调用。然而,虽然 onNext() 被调用,但 onCompleted() 永远不会被调用,我不知道为什么。

我的班级成员定义为:

private let privateVar = Variable<String>("")

在我的 viewDidLoad() 方法中,我设置了 observables:

let localVar = self.privateVar.asObservable().distinctUntilChanged()

localVar.subscribe(onNext:  [weak self] sent in print("first onNext called") )
        .disposed(by: self.disposeBag)

let mappedVar = localVar.flatMapLatest  self.ajaxLoad(var1: $0) .share()

mappedVar.subscribe(
  onNext:  [weak self] queryRes in
    print("onNext called!")
  ,
  onCompleted:  [weak self] in
    print("onCompleted called!")
  
)
.disposed(by: self.disposeBag)

还有我的 ajaxLoad 方法:

func ajaxLoad(var1 myVar: String) -> Observable<QueryResponse> 
  return Observable.create  observable in
    apollo.fetch(query: MyQuery())  (result, _) in
      observable.onNext(result?.data?.myQuery)
      observable.onCompleted()
    

    return Disposables.create()
  

我对 ReactiveX 还很陌生,所以我可能对 Rx 生命周期的实际情况有些模糊。为什么在 flatMapLatest 调用中可能会调用 onNext,而不是 onCompleted?任何帮助,将不胜感激。提前致谢!

【问题讨论】:

【参考方案1】:

flatMap 运算符不会发出您在块内返回的任何可观察对象的已完成事件。

以下代码清楚地说明了这一点。 .just(_) 发出元素,然后发出完成的事件,不会终止订阅。

_ = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
    .debug("before flatmap")
    .flatMap  .just($0 * 2) 
    .debug("after flatmap")
    .subscribe()

事实上,Variable 仅在释放时才发出完成。见source v4.0。 请注意,RxSwift 4 中不推荐使用 Variable,建议您改用 RxCocoa 的类似 BehaviorRelay

deinit 
    _subject.on(.completed)

【讨论】:

但请注意,内部序列中未处理的错误将终止外部序列(flatMap .error(SomeError("an error")) 【参考方案2】:

既然你说你是新人,“有点朦胧”……

请记住,每当localVar 更改时,它都会发出一个新值并调用ajaxLoad(var1:)ajaxLoad(var1:) 的结果然后被推送到您订阅的 onNext 闭包。

还要记住,如果 Observable 发出 .completed,它就死了。它不能再发出任何东西。

所以flatMapLatest 不能完成(除非它的源代码完成。)如果它完成了,它会杀死整个管道并且不会对localVar 进行更多更改通过管道路由, ajaxLoad(var:1) 不会被新值再次调用,也不会被推送到订阅的 onNext 方法。

可以将一系列 observables 想象成一台 Rube Goldberg 机器,其中 completed 关闭机器,error 破坏机器。您应该关闭机器的唯一时间是 source(在本例中为 localVar)完成发出值或 sink(目标,在本例中为 onNext :closure) 不再需要任何值。

【讨论】:

以上是关于RxSwift:为啥 flatMapLatest 从不执行 onCompleted()?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 RxSwift 取消之前的请求

如何使用 RxSwift 传递多个参数?

如何将多个驱动程序与 RxSwift 正确组合?

如何使用 RxSwift 和 Alamofire 库调用来自另一个 API 的响应的 API?

Swift - RxSwift的使用详解32(UITableView的使用3:刷新表格数据)

为啥 `NotificationCenter+Rx` 在 RxCocoa 而不是 RxSwift