RxSwift — ViewController done right™

Côme Chevallier
Smoke Swift Every Day
2 min readAug 17, 2017

The blueprint you’ve been looking for.

Exquisite.

NB: goes hand-in-hand with ViewModel done right; the two are part of the same whole.

In a nutshell

The ViewController part is somewhat more opinionated than the ViewModel because this is where the UI bindings/definitions/helpers reside. As usual, there is no “best” way but some “better” ways and the sole attempt of this post will be to present what has seemed to work well thus far, with readability, separation of concerns, testability and bugs pinpointing in mind.

What should never be in a ViewController

Under any circumstances.

  1. Network calls: these should live in a service struct used by the ViewModel, with the ViewController only getting either a result or an error to handle [upcoming post on architecting services]
  2. Data processing: it should be done in the ViewModel unless it directly relates to a subclass of UIView (example: the ViewModel exposes an array of positions and the conversion to frames happens in the ViewController)
  3. UI / helpers implementations: they should all reside in some dedicated extension

Recipe for a robust ViewController

A ViewController binds the exposed Observable s from the ViewModel to the UI, and features all sorts of side-effects related to them than perform changes to the UI. It is the boundary between what a user can and can’t see.

Let’s take a look at the basic structure and break it down from top to bottom:

  1. A ViewController always conforms to BindableType; if you don’t know why, please refer to Coordinator pattern done right. The two bindings here are basically equivalent: a tap on a button pushes a new scene from the coordinator (the reference to which resides in the ViewModel) and showcase the conciseness allowed by using Action
  2. UI elements and initial setup are thrown into their own extension to de-clutter the ViewController’s core. Because an extension cannot have store properties, UI parts are implemented as class func s. The underscores before their names exists simply because the compiler complains otherwise (this might not be the case as of your reading of this post)

--

--