Question about the conditional sentence of Observable. (RxSwift)

Viewed 57

I tried to create a function runsample() that uses multiple observables as below.
If I meet a specific condition in the middle of the stream, I want to start from the beginning of function.
(foo1() in the example below)

In this case, how do I modify the runsample() function?

class SampleClass {
    ////////////////////////////////
    // private
    ////////////////////////////////
    private func foo1() -> Observable<String> {
        // Do something
        return .just("TEST")
    }
    
    private func foo2() -> Observable<Bool> {
        // Do something
        return .just(false) // or true
    }
    
    private func foo3() -> Observable<String> {
        // Do something
        return .just("Result")
    }
    
    ////////////////////////////////
    // public
    ////////////////////////////////
    public func runSample() -> Observable<String> {
        return Observable.just(())
            .flatMap { [unowned self] _ in
                self.foo1()
            }
            .flatMap { [unowned self] _ in
                self.foo2()
            }
            // I want to retry foo1() when foo2() is false
            // I want to make foo3() run only if foo2() is true.
            .flatMap { [unowned self] _ in
                self.foo3()
            }
    }
}
1 Answers

Based on your comment, this is what you want:

func runSample() -> Observable<String> {
    struct NotValid: Error { }
    return Observable.deferred {
        foo1().flatMap { _ in
            foo2().do(onNext: { isValid in
                if !isValid { throw NotValid() }
            })
        }
    }
    .retry()
    .flatMap { _ in foo3() }
}

It's a very strange requirement you have, but it's doable. I expect this is an X-Y problem though.


You really want to retry foo1()? That would imply that it failed but it obviously didn't. In any case, this will do what you want:

func runSample() -> Observable<String> {
    foo1()
        .flatMap { [foo2] _ in
            foo2()
        }
        .flatMap { [foo1, foo3] isTrue in
            isTrue ? foo3() : foo1()
        }
}

This function will return an Observable. Every time that Observable is subscribed to, the first foo1() will be activated.

Every time the first foo1() emits a value, the value will be ignored (which is quite odd) and foo2() will be called. This will generate a new Observable which will be subscribed to.

Whenever any of the Observables generated by foo2() emit a value, if the value is true foo3() will be called, otherwise foo1() will be called. Whichever one is called, its Observable will be subscribed to.

The entire function will emit all the values that any foo1()s or foo3()s Observables emit.

Importantly for this example, you do not need to start with Observable.just(()).


Thinking about it, I'd prefer something like this:

func runSample() -> Observable<String> {
    Observable.zip(foo1(), foo2())
        .flatMap { $0.1 ? foo3() : .just($0.0) }
}

That way I don't have to run foo1() twice.

Related