Custom bindings with RxSwift

Intro

After I did some convenience operators of my own, which really made things easier while writing code I thought I’d be a good idea to look into building more stuff on my own.

It helps learning and it’s healthy :)

Binding to make a view visible

I noticed there is a binding on the hidden property of UIView but sometimes the code just reads better when you don’t have to think of hiding something but rather showing something.

So I thought since I can check out the source code for rx_hidden how hard could it be to make my own rx_visible?

So I just copied over the code and made my first bindable sink:

extension UIView {
    public var rx_visible: AnyObserver<Bool> {
        return UIBindingObserver(UIElement: self) { view, visible in
            view.hidden = !visible
        }.asObserver()
    }
}

I know that isn’t a great departure from rx_hidden but sometimes it really makes more sense (and it’s more readable) to use rx_visible. Let’s look:

//longer, logic is reversed
isEnabled.map {enabled in !enabled}.bindTo(messageView.rx_hidden)

//short and sweet
isEnabled.bindTo(messageView.rx_visible)

I really like the latter a bit better! So far so good :)

Binding for becoming and resigning first responder

Next - I felt like building something that would actually add functionality it isn’t already in.

In the project I’m currently working on I have a search bar and I have few buttons that show and hide the search bar depending on what the user wants to do.

Therefore I thought it’d be great to make my own bindable sink for being a first responder.

extension UIResponder {
    public var rx_firstResponder: AnyObserver<Bool> {
        return UIBindingObserver(UIElement: self) {control, shouldRespond in
            shouldRespond ? control.becomeFirstResponder() : control.resignFirstResponder()
        }.asObserver()
    }
}

The example isn’t more complex than the previous one. It’s a bindable Bool property, which either makes the control become or resign first responder.

Now I could group the show and hide buttons into one observable:

let searchBarActive = [btnSearch.rx_tap.replaceWith(true), searchBarBtnCancel.replaceWith(false)].toObservable()
  .merge()
  .startWith(false)
  .shareReplay(1)

And besides all the other changes in the UI make the search bar active or force it to lose focus:

searchBarActive.bindTo(searchController.searchBar.rx_firstResponder)

Neat! Since I started writing rx code I’ve really grown to dislike having if operators (also var but that’s a whole other story)

Conclusion

Okay so creating simple on-the-fly cocoa bindings is easy. But is it worth it if it’s so easy?

I like bindings better than writing code to update the UI. No if and no closures to update the UI - no problem. I know other people prefer to not use RxCocoa at all and just use RxSwift and update the UI themselves.

I guess either is okay :)

Do you know a better way to do any of this? Seen a bug? Ping me on Twitter.

Hope that post was helpful, and if you want to get in touch you can find me here

Share this post:


If you'd like to learn how to create professional production apps with RxSwift, the best resource out there is the RxSwift book written by Florent Pillet, Junior Bontognali, Marin Todorov, & Scott Gardner.

It features 20+ chapters covering the basics, the Rx operators, and advanced topics like testing, error handling, and app architecture.

Available from Ray Wenderlich: » Learn more.
Tags// , ,