Keeping your UIViewController clean in Swift

One of my biggest interest when it comes to coding is code quality and code structure. Code often grows complex over time and it can be hard not introducing bugs and making code that is difficult to refactor, maintain and read. A common issue I think many iOS developers have experienced is related to the UIViewController class. This class is very central when it comes to native iOS development. It handles the logic behind a single screen or parts of a screen displayed to the user. Also Apple does not provide any good guidance to avoid this.

I have based this post around the suggestions from this other blog post where the author discusses common bad practices with over-using the UIViewController:

http://doing-it-wrong.mikeweller.com/2013/06/ios-app-architecture-and-tdd-1.html

He lists a few common uses for the UIViewController which could be considered bad.

  1. View setup and custom layout code
  2. Core data code
  3. Delegate for everything
  4. Accessing global states (singletons)
  5. Navigation logic

I mostly agree with the author and want my classes and methods to be as small as possible as well as only have one single responsibility. iOS ViewControllers tend to become way to large and like the author says, if you do not put in effort to restructure and refactor your ViewControllers, your app will so only consist of enormous ViewControllers.

MVC Twitter link

 

A good starting point for anyone who wants smalled ViewControllers is to install the XCode Alcatraz plugin Luft which warns you (coloring the line number view red) when your ViewControllers get to big. I like the idea!

Here are my thoughts on the five common pitfalls above:

View setup and custom layout code

No matter if you are using storyboards, nib/xib files or setting up your UI via code, with or without auto-layout there tend to be modification, setup or manipulation of UI elements in the ViewController. I firstly recommend that you use auto-layout as this saves you lines of code trying to make the UI adjust in smart ways to have dynamic layouts. This can be difficult and come with trade-offs when developing with Xamarin/C#. But in reducing code complexity and having a dynamic UI, it’s hard to beat.

The author suggest that all custom UI code should always be in a UIView sub class which seems reasonable. At least decouple it from the ViewController in some way. If you handle auto-layout via code, this can also be reduced significantly via help methods or even better extensions to UIView. Here is a reoccurring code I’ve used in several iOS projects, which handles the common task of animating the bottom constraint of a UITableView of match the animating of a keyboard showing:

Core Data code

Even if XCode default places Core Data logic in your AppDelegate or UIViewController, this should of course be placed in a class responsible for managing storage or data. Personally I would place this in a central place in the app. I think Singletons are overused and should be avoided whenever possible. I normally structure my code so that I have instances (not Singleton) in my AppDelgate (which itself is a Singleton). My AppDelegate often look something like this:

By placing the managers as instances in the AppDelegate I have more control of their life cycle. May not differ that much from normal Singletons, but at least now I have central place where I manage and store my managers. I can also easily reach them via AppDelegate.sharedDelegate().dataManager.

Delegate for everything

This is one of the more interesting one I think. A common bad practice is when using UITableViewController or when delegating UITableViewDataSource and UITableViewDelegate to the ViewController:

Here developers often also place other delegates such as UIPickerViewDataSource, UIAlertViewDelegate and custom delegates for handling delegation from other UIViewControllers and views. However Swift makes both structuring delegate implementations much easier. Using Swift it has become a good practice to extend your custom UIViewController for each implementation of a delegate and let that extension implement that delegate. For example:

This also allows you to place your UITableViewDelegate and UITableViewDataSource extensions in another file. I usually try to place my TableView extensions in one file and the rest of my ViewController extensions in another. The UITableView extension often look something like this:

This will often greatly reduce the size of your ViewController class. I can also the move out helper methods that are only used by your extensions. This one of the primary ways to keep your UIViewController clean in my opinion.

Unfortunately the extensions cannot hold any instance variables, so you still have to keep state variables for your UITableView in your base ViewController. You can if you have a lot of instance variables only related and used by your UITableView extension move this to a ViewModel inner class that you at least place in your MyTableViewDataSource class.

This allows you to keep one viewModel class for your ViewController which does not contain any variables related to your tableView. You still however need to keep a reference in your MyViewController as extensions cannot have instance variables.

Accessing global states (singletons)

The author above discusses that many inexperienced developers tend to access a lot of application wide singletons in order to store or pass data. For example:

Even if I would not contribute it to my own list of bad practices to specifically UIViewControllers, it’s still a bad practice. You should not pass data between ViewController this way, and be careful of storing data in singletons for various reasons (see http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons). Also, as a refactoring maniac I would instantly create a help method for that awful long code line and place it in my AppDelegate.swift file:

The use of singletons in your ViewController will introduce more hard coupled links to other part of your application. Instead you want simple small loosely coupled parts that have as few and clear dependencies to other parts as possible. This is a wider discussion I will not fit in this blog post.

Navigation logic

The author also argues that the navigation logic should not be present in a ViewController. Moreover it shall not know what kind of context it is used in (which I agree to). It does not need to know where it was started from, or which view it is embedded in. However, I have not yet though on how or why to refactor out navigation logic. This is perhaps because I am so used to Storyboard where it is difficult to achieve good separation of View and Navigation Logic. I have to look into this more.

Summary

Swift Protocol Extensions have made it easy to separate delegates and parts of code related to UIViewController both into separate parts and files, which makes the code more easy to structure, maintain and read. Using Auto Layout decrease the need for UI logic in your view controllers. Also putting your custom UI setup code either in UIView subclasses and/or creating them in Storyboards or nib/xib files reduce the amount of code in your ViewController. Overall refactoring of duplicate and reusable code into subclasses or extensions can greatly reduce complexity as well. Also making sure that logic for handling Core Data, Networking and other separate task are placed in other locations than in UIViewController should always be the practice.

Improving further

This is my first blog post and there are more interesting topics related to UIViewController, Extensions, Delegates, separation of code that can be discussed. I am always open to discussions and improvement. If you have any comments, questions or even better suggestions on how to keep your UIViewController clean, please post below.

Leave a Reply

Your email address will not be published. Required fields are marked *

*