RxSwift 结合 observable 和条件
Posted
技术标签:
【中文标题】RxSwift 结合 observable 和条件【英文标题】:RxSwift combine observable with conditional 【发布时间】:2017-08-25 02:02:15 【问题描述】:我正在尝试组合 observables,并且我希望它们按顺序运行(例如,执行步骤 1,如果满足某些条件则执行步骤 2,如果满足某些条件则执行步骤 3)。我发现这样做的唯一方法是在每个步骤中添加条件,我不喜欢这样做:这是我当前解决方案的示例:
enum Status
case unknown, exists, missing
func refresh() -> Observable<Status>
return checkLocalStatus()
.flatMapLatest $0 == .exists ? Observable.just($0) : self.attemptRemoteStatusOverride()
.flatMapLatest $0 == .exists ? Observable.just($0) : self.attemptRemoteStatusUpdate()
private func checkLocalStatus() -> Observable<Status>
return Observable.create observer in
// Regarding Maxim Volgin's comment, here I'm converting a closure to an
// observable... why not use Observable.create?
self.cache.status (status) in
guard status != .exists else
observer.onNext(status) // .exists
observer.onCompleted()
/* I don't want this condition to be here */
if ignoreRemote
// status is !exists and we should ignore remote, throw error
observer.onError(Errors.remoteDisabled)
observer.onNext(.missing)
observer.onCompleted()
private func attemptRemoteStatusOverride() -> Observable<Status>
return remote.statusOverride()
private func attemptRemoteStatusUpdate() -> Observable<Status>
return Observable.create observer in
// Regarding Maxim Volgin's comment, here I'm converting a closure to an
// observable... why not use Observable.create?
self.remote.updateStatus (status, error) in
guard error == nil else
observer.onError(error!)
observer.onNext(status)
observer.onCompleted()
我想做这样的事情:
func refresh() -> Observable<Status>
return checkLocalStatus()
.if( $0 != .exists && !ignoreRemote ,
then: self.attemptRemoteStatusOverride() ,
else: return $0 )
.if( $0 != .exists ,
then: self.attemptRemoteStatusUpdate() ,
else: return $0 )
或
func refresh() -> Observable<Status>
return checkLocalStatus()
.flatMapLatest(if: $0 != .exists && !ignoreRemote ) self.attemptRemoteStatusOverride()
.flatMapLatest(if: $0 != .exists ) self.attemptRemoteStatusUpdate()
我找不到任何像我正在尝试的东西,所以我认为我做错了。有没有人对如何走这条组合可观察的路线有建议或替代方案?我已经看到使用combineLatest
并根据其他结果返回一些结果的示例,但我只想在满足条件时执行每个步骤。 combineLatest
将执行每个步骤(每次),然后我将根据其他步骤的输出返回某些步骤的结果。我也开始考虑编写自定义运算符,但想不出办法。
更新:我已更改为以下内容并计划编写一个删除重复的方法:
func refresh() -> Observable<Status>
return checkLocalStatus()
.flatMapLatest status -> Observable<Status>
guard status != .exists && !ignoreRemote else
return Observable.just(status)
return self.attemptRemoteStatusOverride()
.flatMapLatest status -> Observable<Status>
guard status != .exists && !ignoreRemote else
return Observable.just(status)
return self.attemptRemoteStatusUpdate()
【问题讨论】:
作为一般规则,除非您正在构建库/框架,否则不应使用“Observable.create()”。其次,你的‘Observable’只发出一个‘onNext’事件,那么为什么不用‘Single’而不是‘Observable’呢?您能否说明您打算如何使用这些可观察对象?因为你似乎在尝试解决一个你一开始就不应该遇到的问题。 为什么不使用Observable.create()
是“一般规则”?我有服务外观,我想返回 observables 而不是使用闭包。这似乎是 RxSwift 的常见模式。我在哪里可以阅读有关此规则的更多信息?我不知道Single
,所以这很有帮助。
基本上,因为它是更多的工作。在像您这样的简单情况下,首选的解决方案是使用“.just()”或“.from()”。对于服务外观,最好使用 '.switchEmpty()'、'.retryError()'、'.catchErrorJustReturn()' 和我个人最喜欢的 '.switchLatest()'
【参考方案1】:
也许您需要一些带有条件的 flatMapLatest 函数版本?你可以用你想要的语法来做一些你想要的功能:
extension Observable
func flatMapLatest(condition: @escaping (E) -> Bool, then: @escaping (E) -> Observable, otherwise: @escaping () -> Observable) -> Observable
let observable = self.shareReplayLatestWhileConnected()
let observableCondition = observable.map( condition($0) ).shareReplayLatestWhileConnected()
let observableThen: Observable<E> = observableCondition
.filter( $0 )
.withLatestFrom(observable)
.flatMapLatest( then($0) )
.shareReplayLatestWhileConnected()
let observableOtherwise: Observable<E> = observableCondition
.filter( !$0 )
.withLatestFrom(observable)
.flatMapLatest( _ in otherwise() )
.shareReplayLatestWhileConnected()
return Observable<Observable<E>>
.from([observableThen, observableOtherwise])
.merge()
并使用它
func refresh() -> Observable<Status>
let condition = (status: Status) -> Bool in
return status == .exists
let then = (status: Status) -> Observable<Status> in
return Observable.just(status)
return checkLocalStatus()
.flatMapLatest(condition: condition, then: then, otherwise: self.attemptRemoteStatusOverride)
.flatMapLatest(condition: condition, then: then, otherwise: self.attemptRemoteStatusUpdate)
【讨论】:
这是有道理的,但是,我希望这些私有方法做他们应该做的任何事情,这样它们就可以在其他地方调用。我希望条件逻辑保留在refresh
方法中。如果attemptRemoteStatusOverride
被调用,那么它应该尝试远程状态覆盖。我已经用可行的方法更新了我原来的问题,我只是不知道是否有另一种方法可以有条件地组合可观察对象。以上是关于RxSwift 结合 observable 和条件的主要内容,如果未能解决你的问题,请参考以下文章
RxSwift。结合最新。并不是所有的 observables 都发出了