RxSwift结合了observable和conditional

时间:2017-08-25 02:02:16

标签: conditional observable rx-swift

我正在尝试组合observable并且我希望它们按顺序运行(例如,执行步骤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()
        }
}

1 个答案:

答案 0 :(得分:1)

也许你需要某些版本的flatMapLatest函数有条件?你可以使用你想要的语法创建一些你想要的功能:

Any

并使用它

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()
    }
}