How use State Design Pattern to create a Stateful ViewController?

Rodrigo Cavalcante
Cocoa Academy
Published in
3 min readAug 29, 2018
State machine

What the hell 🔥 is a Stateful ViewController? A Stateful ViewController is then name given by us to a ViewController that has many states and should be able to change views or components based on current state.

Create a Stateful ViewController may be tricky, first we can have different loadings and error views for certain screen e.g. in our LoginViewController we have a loading inside our UIButton and error messages should be handled with a custom alert. Our HomeViewController should show a default loading view and default error view that knows how to handle an Error.

We wish to build it in a way that we don't have to repeat code or behaviors in many view controllers.

We can use a State Design Pattern to handle it. The State pattern is:

A behavioral software design pattern to allow an object to alter its behavior when its internal state changes. The state pattern can be interpreted as a strategy pattern which is able to switch the current strategy through invocations of methods defined in the pattern’s interface.

Defining our state

We defined some states like .success , .loading, and .error(error) and we thought will be great to create a protocol and add it to our ViewController.

The problem with this approach is that every view controller will have a giant switch case and probably a lot of repeated code.

😒: —" Yeah! Yeah, but you can solve this creating funcs" you said.

😅: — Ok! But this will not solve our problem, only disguise it.

And another problem is: “What happens if we add another state?” Yes! we need to add it to every switch case or create a default. Adding another case will make us modify every class that uses our Statable protocol breaking the open closed principle.

Creating a single state protocol

We thought it will be better if we changed our enum and protocol for a new protocol:

So much better now! This eliminated the switch case problem but not exactly what we want.

And now every view controller need to have this three methods even if has a default loading view or error view. In other words, we still are repeating code.

Truly, this change does not make anything better. 😓

I usually say:

If you have a protocol method that has a default implementation or will not be used in every class/struct that method should not be there.

Breaking our state protocol

Some view controllers do not need to implement setLoadingState() or setErrorState(error: Error) this will be handled by default classes. So we decided to split our protocol into three.

That's will be great because we can create default loading and error views:

Default loading view
Default error view

And also add custom behaviors to some UIViewControllers e.g. If you would like to change the way a loading is done in a defined ViewController or a custom alert to show error message you can handle all three protocols in the ViewController like:

Handling default states

Finally, we can create a decorator in our ViewController to handle all states and switch between them every time we need.

Conclusion

With this approach, we can have custom loadings and errors views when we need and default implementations when a custom one is not required. We can create many different classes to handle loadings making our DefaultLoadingState close for modification and open for extensions.

We mixed the State Design Pattern and the Decorator Pattern to create a StatableViewController that will handle states in our view controller. Using dependency injection we can change loading and error behaviors from our controllers in a single entry point.

Ps: If you like this post, share it on Twitter, recommend it on medium, or both =). This really helps me to reach more people. Thanks a lot.

--

--