All posts
iOS

RxSwift by Examples
#2 – Observable and the Bind.

Łukasz Mróz

Łukasz Mróz

Edit 18.01.2017: This post was updated to Swift 3.0 and RxSwift 3.1

In the first chapter we’ve learned the basics about RxSwift and RxCocoa (if you haven’t seen it yet, I really encourage you to do so!) . The time has come and we will expand our knowledge in a reactive way. Today we will talk about bindings.

rx_bindings

Don’t worry, binding just means connecting and we will connect our Observables with Subjects. There is some terminology that we haven’t learned before, so…

Definitions

here_we_go

Before we start we need to get in touch with some definitions. We learned about Observables and Observers and today we will learn about other types.

SubjectObservable and Observer at once. Basically it can observe and be observed.
BehaviorSubject – When you subscribe to it, you will get the latest value emitted by the Subject, and then the values emitted after the subscription.
PublishSubject – When you subscribe to it, you will only get the values that were emitted after the subscription.
ReplaySubject – When you subscribe to it, you will get the values that were emitted after the subscription, but also values that were emitted before the subscription. How many old values will you get? It depends on the buffer size of ReplaySubject you subscribe to. You specify it in init of the Subject.

Okay, okay. Too many subjects. Let’s simplify it a little bit. You are having a birthday party 🎉 and you are opening the presents you’ve got.

Birthday party!

You’ve opened first, second, third gift. And whoops! Your mom was cooking some delicious food and is late to the opening party. As a mom, she just has to know what presents you’ve got already. So you tell her about them. In Rx world you’ve sent observable sequence (presents) to the observer (your mom). What’s interesting is that she started observing you after you already emitted few values, but she got whole info anyways. For her we are a ReplaySubject with buffer = 3 (we save 3 latest presents and give it every time a new subscriber appears).

You are still opening presents and there you see that two of your friends (Jack and Andy) were also late to the party. Jack happens to be your close friend so he asks what have you opened so far. As you are kinda angry that he missed a part of it, you tell him only the latest present you’ve opened. He doesn’t know that there were more of it, so he is happy with it. In Rx world you’ve sent only latest emitted value to the observer (Jack). He will also get the next values as you emit them (next presents you will open). For him we are a BehaviorSubject (we kinda changed the Subject 😎).

There is also Andy, who happens to be just a friend and doesn’t really care about the presents you’ve opened so he just sits down and waits for the rest of the show. As you can imagine, for him we are just a PublishSubject. He just gets values that are emitted after the subscription.

One more thing...

There is also something called Variable. This is wrapper around BehaviorSubject. The thing is, you can only submit the .onNext() event (when using BehaviorSubject you have direct access to sending .onError(), .onCompleted()). Also, Variable automatically sends .onCompleted() event when it’s being deallocated.

Alright, enough with definitions. Let’s try it out!

Example

View model example

We will create simple app that will connect ball color with position in view and also we will connect view’s background color with the ball color.

Leo pls

First let’s create a project as we created in a tutorial before. We will also use CocoaPods and in addition to RxSwift and RxCocoa we will use Chameleon to nicely connect the colors. Our Podfile should look like this:

After setting up the project we can start coding! First we will draw circle in the main view of our controller. We will do it from code, but if you want to do it in Interface Builder – you are free to go. Example of creating that view looks like one below:

That code should be self-explanatory (we just created rounded UIView) so we will just move forward. Next step would be to move our ball on pan gesture. In order to do that let’s add UIPanGestureRecognizer and change the frame of it:

Perfect! Our app should now look somewhat similar to the one below:

View Model Example app step 1

The next step would be to bind something! Let’s connect position of the ball with ball’s color. How to do that? First we will observe ball’s center position using rx.observe() and then bind it to a Variable, using bindTo(). But what does binding do in our case? Well, every time a new position is emitted by our ball, the variable will receive a new signal about it. In this case our variable is an Observer, because it will observe the position.

We will create this variable in a ViewModel, which will be used to calculate UI things. In this case every time our variable will get a new position, we will calculate new ball’s background color. Easy, right? 🤔

Now we need to create our ViewModel. It will be really simple one, because we will have only 2 properties: centerVariable which will be our observer & observable – we will save data to it and we will get it. And the second one will be backgroundColorObservable. It is actually not a Variable, but only an Observable.

Now you might ask “Why is centerVariable a Variable, but backgroundColorObservable is an Observable?” And that is a brilliant question! See, our observable center of ball is connected with centerVariable. It means that overtime the center changes, centerVariable will get the change. It is then an Observer. Also in our ViewModel we use centerVariable as an Observable, which makes it both Observer and Observable which is just a Subject. Why Variable and not PublishSubject, ReplaySubject? Because we want to be sure we will get the latest center of that ball every time we subscribe to it.

backgroundColorObservable is just an Observable, it is never bound to anything so it makes perfect sense to leave it just as an Observable.

Alright! Done with the theory, let’s code! Our basic ViewModel should look like this:

Perfect. Now we need to setup our backgroundColorObservable. We want it to change based on new CGPoint produced by centerVariable.

Step by step:

  1. Transform our variable into Observable – since Variable can be both Observer and Observable, we need to decide which one is it. And since we want to observe it, we transform it into Observable.
  2. Map every new value of CGPoint to UIColor. We get the new center that our Observable produced, then based on (not-so) really complicated math calculations we create new UIColor.
  3. You may notice that our Observable is an optional CGPoint. Why? We will explain it in a second. But we need to protect ourselves and in case we get nil, return some default color (black in our case).

Okay. We are really close to the end. We have now Observable that will emit new background color for a ball. We just need to update our ball based on the new values. Now that’s really easy. It’s similar to our part #1 of the series. We will subscribe() to the Observable.

As you can see we’ve also added changing the background color of our view to the complementary color of our ball. Also we have the check if complementary color is the same as the balls’ color (we want to see it at least!). But that’s a feature, not that main task. You need to add this code rather in the setup() method, so it looks similar to:

And you’re done! The whole task of manipulating colors without delegates, notifications and that whole boilerplate code we always use for that type of tasks. The result should be somewhat similar to the one from the beginning of the Example.

View model example

Now you can try to customize it! Maybe add binding between center and the ball size? Then try to change its cornerRadius based on its width and height? It’s really up to you but I think that with Rx that tasks are really delightful.

That’s it for today and as always visit our GitHub for whole project and see you guys next time!

P.S. I try to implement more examples on a weekly basis so subscribe(😎) to our RxSwiftExamples repo!

Read other articles about RxSwift

» RxSwift by Examples #1 – The basics.
» RxSwift by Examples #3 – Networking.

Newsletter

The post is created by Droids On Roids Team Member.
We would love to take care of your business.

Leave comment

  • I’ve never tried animations with RxSwift. Looks cool. Thanks for that!

    • Łukasz Mróz

      Sky is the limit! Thank you! ☺️

  • LuisGL100

    Great article! But you didn’t explain why the Observable is an optional CGPoint

    • Łukasz Mróz

      Oh right… Basically because of the fact that when you do rx.observe you can get nil or a value, due to that fact that the string you provide as a key path might not be available.

  • Yi Gu

    I could put all code to circleMoved(), which means I could do all in Tap Gesture selector function — then what’s the good of using RxSwift here?

    • Łukasz Mróz

      Well, to be frank, the whole RxSwift is built in on top of currently implemented features, so you could say that about everything if you want to. Here we show how to implement a feature using model, to extract the logic from ViewController. Then you can see how to bind things together using RxSwift.

      • Yi Gu

        Yeah yeah, I understand the point. I just feel it is not as simple as expected using RxSwift here.

  • Shpasta

    Thanks for the article!
    Why didn’t we do something like this:

    circleView
    .rx_observe(CGPoint.self, “center”)
    .subscribeNext{ [weak self] point in
    // convert CGPoint value to UIColor
    // for self.view.backgroundColor
    }
    .addDisposableTo(disposeBag)

    • Łukasz Mróz

      Hey! Thanks for the question. Of course we could do that, but with the way I presented you can easily unit test the model, because you have separated logic.

      • Shpasta

        Wow, it was quick 🙂
        Good approach, thanks!

  • Michał Ronin

    Thanks much for the series! Fun to read, easy to follow. Found a small bug in the code: the circleMoved function requires an unnamed argument in order to work with the selector. Cheers!

    • Łukasz Mróz

      Hey Michał, thank you very much, really appreciate the feedback 🙂 About the bug, you are right, sorry about that, really easy to overlook something with the upgrade to Swift 3.0, so thank you for that as well!

  • wei zhang

    Thanks for the tutorial

    But I got a problem when following this example, I found out when I move the color ball, the center positon is not sent to centerVariable…
    Could you give me some clues?

    Thank you 🙂

    • Łukasz Mróz

      Hey @disqus_v09j6kGHxr:disqus, does the example work for you? Do you have troubles implementing it on your own? If yes, we would need some code for that 🙂

  • Tal Shrestha

    Very nice!
    Why use centerVariable.asObservable().map and not centerVariable.asObservable().onNext ?

  • Lucas Ferraz

    Very good analogies, thank you.