How to separate view controllers from their view logic

Have you ever gone into a view controller and had the same sensation as you have when you enter a room after a huge party? It happened to me more than once. The last I saw was more than 1.600 lines long. How can you find anything inside? How can you test it, refactor it, change it or add new features?

Making our View Controllers lighter makes our life happier. Our applications have long lifetimes and we will have to read the code we write a lot of times. The problem is that when we start to learn how to develop for the iOS platform using Apple’s examples, we get used to having a lot of things inside the VC classes. Business logic, database, view logic, …

This first post talks about how we can separate our view logic from the view controller. As a usual practice we get the view controller to create and/or control all the hierarchy of the view (using xib or loadView method). We make the VC aware of all the little details of the view like the layout, the animations, how to fill it, respond to every event of the subviews… That makes the VC harder to understand, and very coupled on how the view is showed.

The VC is a responder, its responsibility is to respond to the events the user creates using the interface. It controls the view and the events that come from it. It shouldn’t implement the view. If a view uses a UITableView or a UICollectionView, these are only details. Also I see the views as very specific and asynchronous beasts, it’s preferable to keep them caged, and more if you want to test your VC.

Here are some tips on how to design the view components

Create classes for views

First of all, create a class for the view. This class will contain all the details of the view and will be an abstraction for the VC. The interface of the view will consist of methods to change its state and a way or ways to retrieve information from it. That means that the VC is not coupled on how the view is implemented, only with the features it offers to it.

As you can see there are no IBOutlets in its interface or any information about the view subviews. That’s because all of these are implementation details. If you put them in your interface you will couple your View Controller with the fact that it is using a UITableView to show the login and password fields. You don’t want that because your designer can come tomorrow and change it to UITextFields and UILabels. This way the view can change without changing the ViewController

Use View Models to encapsulate the information the view displays

As you can deduce from my example I’m using an object the view defines to encapsulate an abstraction of the information the view shows. That’s better than having the two string properties defined inside the view interface because you can use the view model as a communication tool.

The view model is defined by the view and contains the information the view can show and/or modify. The view controller creates the view model and fills it with information that it knows how to retrieve from the model. Once created the instance is assigned to the view. The View Controller also subscribes to any property the view can change using KVO, usually on viewDidAppear (and unsubscribe to viewDidDisappear).

This way if you want the view controller to know when the view changes the data of the view model, you don’t have to create all these painful delegate methods and the view doesn’t have to be coupled to this need. The definition of the view model does it for you and gives you a clean and easy way to have your view and view controller data synchronized.

Reference your subviews at the private interface

You need to have references that point to your subviews, all this UILabels, UITableViews or whatever objects you are using to create your interface. All of these are implementation details and shouldn’t be visible to the other classes. The best place to define them is using properties in the private interface of the view.

If you do that, the day you want to change this UITableView for two UILabels and two UITextFields you will only have to change this class, not the view controller. Also this removes all these details out of your already huge VC.

Use XIBs to define your layout

The XIBs are only a way to define your views not your VC. I think that’s an extended misunderstanding among developers. XIBs are an automated way to create our subviews and layouts. The view controllers use xibs to instantiate our views.

XIBs are a good way to write less code for interfaces, they are perfect to define the layout and the subviews used inside. You can connect the properties of the private interface with the instances of the subviews created by the xib using IBOutlets. At the interface builder you can specify the class of the view, this way the framework knows it has to create an instance of your concrete view subclass:

 

Work with XIB

connect

Use a delegate to comunicate asynchronous events from the view

When the user taps the login button we want the view controller to know it. The view controller knows how to respond to this event. I’m not saying the view controller should know how to login, but we will be speaking about how to separate the VC from this kind of stuff in further posts.

The delegate should be defined in the .h file of the view because it is defining the events that the view can generate. The view will have a delegate property that the VC will be responsible to set. It can be set through the XIB or in the viewDidLoad method depending on your style and both works for testing purposes.

It’s preferable to use delegate instead of blocks for this kind of events for readability inside the view controller. This way you can have all the methods of the delegate in the same section of the view controller code, and not spread inside the viewDidLoad method, but it’s a matter of style.

You can also use delegates to verify the format of the text or data entered in the view. The view controller has more knowledge about the system and sometimes the data verification can be related to the model.

Use blocks for asynchronous operations

The views have plenty of asynchronous operations like showing an animation or asking for confirmation to the user. In these cases I use blocks. I think it’s preferable for readability, it gives you a feelling of continuity inside your code.

Also an operation can be used in different places of your VC, and do different things for each case at the its completion.

This strategy is also useful for testing purposes. I can easily create a test double for the view with a fake implementation that only calls the block. That lets me test the view controller without messing around with sync issues simulating both cases, when the user confirms or not, depending on the test case.

The datasources are in the view not inside the VC

WHAAAAAAAAAT? Everyone knows that the VC’s are THE datasources, the same way we know that Santa Claus is really the parents. All the examples from Apple do it that way. But think about this, if you want to change the view from the UITableView implementation to one with UILabels and UITextField you will have to change your VC… That’s coupling…

Also you have all the information you need inside the view model, why delegate this responsibility to the VC? The table view is only an implementation detail from the view.

You can separate them in classes that the view instantiates and assign the view model to them too. You should do that for two reasons: Readability and testing. Readability because you encapsulate the creation of the cells and their configuration inside an object. And testing because you can test some parts of the datasources: number of cells, number of sections, that asking for cells don’t return a nil pointer. All the things that aren’t too specific.

Conclusions

I know that some of these practices seems to be against what are the standards from Apple. There’s no place at the Apple guideline where they say that separating your view from the view controller goes against the framework. Or that you have to define your IBOutlets in your VC. That works on small systems but when they grow and become more complicated you need to separate your responsibilities, and make your code readable and testable.

You can think that adding this level of indirection will make you a slower programmer. Of course that has a cost in time but once you are used to it, it doesn’t take that much time and the benefit in the future will make you more agile. You will feel that when reading your code, it will be faster to find what you are seeking.

You can use these techniques together or only take a subpart of it. I will be happy to discuss all these techniques if anyone is interested, only make a comment, mail me or tweet me 🙂

If you want to see all these techniques in action visit my Github repository where I maintain a project illustrating all of them.

This entry was posted in Architecture, Clean Architecture, iOS, View Controllers and tagged , , , , , , . Bookmark the permalink.

10 Responses to How to separate view controllers from their view logic

  1. Pingback: Testing part I: View Controllers | Software Design thoughts

  2. Luis Ascorbe says:

    Hi Jordi!

    Great post, thanks for writing and sharing it!

    I think mixing KVO, blocks and delegates looks like too many things for the same VC. I understand your concepts, why you use each one in which case, but why do not use just one method? Otherwise it could be confusing, IMHO.

    Also, I’d put the VC directly on the root of the group (Login), I think it’s a very important class, and should not be inside another folder.

    Cheers,
    Luis.

    PS: In Objective-C you should not start a method with the “get” prefix ;] (i.e. getLastLogedUsername should be lastLogedUsername). http://marker.to/Ln4WmE

    • KPM says:

      Actually, get methods exist but have a different meaning. A method that begins with get is expected to return void (or BOOL) and put the result in the first argument, passed by reference. Compare:
      – (char *)bytes;
      – (void)getBytes:(char **)bytes;

  3. Rich Waters says:

    Great article.

    I especially like the part about dataSources being part of the view and not the controller. As I’ve been rewriting code I wrote from 5 years ago, I have realized the same thing myself. The dataSource is part of the view and not the controller.

    I would disagree with you about Nibs, though. I embraced these for years, but I’ve come to learn that is is best to avoid these all together. When you create your views with code, you get to reap the benefits of the IDE when its time to refactor and you get to use git (or other source code control) to its fullest. Also, Nibs are one of the reasons *why* we end up with so much in our view controllers. Removing nibs is liberating.

  4. 0oneo says:

    Great post, thanks

  5. jre says:

    hey, do you have a twitter?

Leave a Reply