The basic structure
We’ll group the screens of our Red & Green App semantically into units. Every unit comprises the following components:
ViewModelProtocol is used to further encapsulate the communication between the ViewController and ViewModel.
Our app has a main screen where we get to pick red or green color. Picking the red color takes us to the red screen, and the green color takes us to the green screen.
- mainView — defines the visual part of the screen and configures the actions on it
- viewModel — separates the logic of the UI part; in the MVVM-C pattern it is also in charge of communicating with the coordinator
Let’s dig in and define the main screen. We’ll call it the MainVC:
LoadNibFromEnum you see there is our custom function that we use to call Nibs:
The View is defined with the corresponding XIB, where there are two buttons, which are exposed on the screen so the actions on them can be defined.
The ViewModelProtocol defines all the actions that can be executed on the VC-VM relation. In this particular case, we only need to define actions on the two aforementioned buttons, so this is what we’ll do:
Actions can be defined in multiple way, but we define them exclusively through blocks, for the sake of code legibility.
ViewModel can be a class or a structure which conforms to the ViewModelProtocol, which means that all methods or actions defined in the ViewModelProtocol must be defined in the ViewModel as well.
Then we can finally connect the button actions from the view with the actions defined in the ViewModel:
Our MainView is exposed so we can define all the actions over the buttons in the viewDidLoad and forward every action to the block in the ViewModel.
That way the ViewController doesn’t have to know what’s going to happen next in navigation, and has no responsibilities save for controlling the UI.
Defining the screens
However, we will override the back button navigation on both screens, since we want all transitions to be carried out via coordinators.
The GreenVC and RedVC will look like this:
We made a navigation button and made a custom back button action defined through a block and in the coordinator.
The structure of the screen within the app consists of:
Now let’s define that main coordinator:
In our post “Taming the app flow with coordinators” we already explained how to structure the main coordinator.
What’s important here that there is a root controller that all the new screens are set on, an array in which all the future coordinators will be saved, an onEnd block where the deallocation of the coordinator is executed, as well as a start method that initiates the coordinator and all the flow within it.
Now lets create the main coordinator. It will be a final class, so it cannot be subclassed further, and it will inherit the coordinator object.
Initially, it contains only the start method which calls the private function to start the main flow. Within it, we’ll define the ViewModel i ViewController, as well as all the actions defined in the ViewModel.
At the moment, the Green Button flow and the Red button flow are empty. Since clicking on each button will open a sequence of screens, it’s supposable that the screens are a part of a story. And since we define our coordinators semantically, the best practice is to create a coordinator for every story.
In this example, this means that we’ll create RedCoordinator and GreenCoordinator.
We do that by calling an onEnd block.
So here’s the GreenCoordinator:
Now we can define the function within the main coordinator which we use to call the GreenCoordinator:
It’s a pretty straightforward process: We create the coordinator, start it, add it to stack with the add method defined within the coordinator, define the action for removing the coordinator from the stack, called by the OnEnd block.
We do the same for the Red Screen.
All that’s left now is to start the main coordinator somewhere, and the only logical place is the AppDelegate. In the AppDidFinishLaunching we define the navigation controller which we submit to the main coordinator to execute further transitions.
And that’s about it.
And it all sums up to cleaner code, less responsibility for the Controller and the ViewModel and better separation of concerns.