Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to translate an if-else in RxSwift?

I'm trying to learn the library RxSwift

I have some code like this:

if data.checkAllIsOk()
{ 
    [do things]
}
else
{ 
    [show alert]
}

Now i need to update the data from the server before checking, so i have modeled a getData() that return an Observable.

My current approach is this:

getData()  
    >- flatMap{ (data:Data) -> Observable<Bool> in
        _=0 // workaround for type inference bugs
        return just(data.checkAllIsOk())
    }
    >- subscribeNext{ (ok) -> Void in
        if ok
        {
            [do the things]
        }
        else
        {
            [show the alert]
        }
    } 
    >- disposeBag.addDisposable()

It works (or it should, i'm still writing it), but it feels wrong.. is there a more "reactive" way to do it? What are the most appropriate operators to use?

Maybe returning an error for “false” and use the catch block?

Update

Following the approach suggested by ssrobbi i splitted the 2 branches in 2 different subscribeNext, and used filter to select the positive or negative branch. This is the code resulting:

let checkData=getData()  
        >- flatMap{ (data:Data) -> Observable<Bool> in
            _=0 
            return just(data.checkAllIsOk())
        }
        >- shareReplay(1)
}
[...]
checkData
    >- filter{ (ok) -> Bool in
        ok == true
    }
    >- subscribeNext{ (_) -> Void in
        [do the things]
    }
    >- disposeBag.addDisposable()

checkData
    >- filter{ (ok) -> Bool in
        ok == false
    }
    >- subscribeNext{ (_) -> Void in
        [show the alert]
    } 
    >- disposeBag.addDisposable()

The advantage of this approach is that i can reuse only one of the two branches in other parts of the code, without rewriting the subscribe body (less duplication is always good!)

Update

After some discussions in the RxSwift slack i added the shareReplay(1), so the getData() isn't repeated.

like image 686
hariseldon78 Avatar asked Sep 02 '15 16:09

hariseldon78


1 Answers

So to be honest I'm still learning as well, and I don't have RxSwift in front of me right now (so someone correct me if I'm spewing BS), but maybe I can give lead you into the right direction.

Your solution does work, but as you said it isn't very "reactive". I think the problem is that you have your data flow set up in a way that it has to make an imperative decision on whether to show an alert or do stuff. What should happen, is that instead of getData returning an observable, getData should get whatever data it needs to (whether it's from a network, core data, etc), and then it should update an observable property.

For the do things: Now, you would observe that property, map it to check if it's okay, and subscribe to it like you did, check if it's true, and if it is do things. (and add disposable)

For the alert: You'd do the exact same thing, observing that same property again, but check for the opposite case and do stuff.


I think what's not super reactive about it is that you're synchronously waiting on a response from that getData() function, which creates a scenario where you now have state, whether to show an alert, or do that extra work. They're not derived from the value stream of some other property. Showing the alert and doing things are only related to each other because you set up your code imperatively.

EDIT: Instead of checking with an if statement whether or not that's true, perhaps you could put it through a filter before subscribing instead.

like image 64
ssrobbi Avatar answered Oct 01 '22 05:10

ssrobbi