When one is writing a computer program, one should write compact, logical, and modular components and veer away from source files which burgeon into unwieldy monoliths. In the iOS world, there are some who are turning away from the traditional Model-View-Controller (MVC) design pattern and are experimenting with other architectural patterns in the effort to correct the so-called "Massive View Controller" problem, where the ViewController class has become an unorganized heap of assorted bits. In a future post, I will discuss these alternative architectures in more depth, but for this post, I will detail several real world cases I've seen and how to fix them without having to resort to rearchitecting your entire app so the ViewController is not so massive.
There is no single "right way" for designing an application, but there certainly are some grave missteps which can be easily avoided so your code is better organized, cleaner, and easier to read, maintain and use.
Categories
The Category in Objective-C (otherwise known as Extensions in Swift) is an amazing feature which allows the programmer to extend the capabilities of an existing class, without having to create a subclass. Want to create a custom method for a color or font? Done. Want to extend the functionality of the string class? No problem. Not every programming language has this feature, but once you learn how to implement Categories, they are immensely useful.
In an old project I inherited, I came across a source file that was a little over a thousand lines of code. However, nearly a quarter of that was taken up by just one lengthy method. In this particular case, it was a method used to return a specific color, depending on the character passed in. In this example, several options could be used to reduce the code bloat. Instead of setting values for three different variables (assigning values for the red, green, and blue values), the UIColor can be created and returned for each case, which will cut down two-thirds of the code.
Next, since this is returning a UIColor, this entire method is better placed within a category class, which will also provide the benefit of code reusability so that any other parts of the app can make use of the same functionality.
The new UIColor category class (both header and implementation files) resulted in 225 lines of code after I slimmed down the original method by removing unnecessary braces in a giant switch statement. Another pass could like reduce this even further, but for an initial pass, that was a nice improvement for half an hour's worth of work.
After further inspection of this project, I discovered that this same lengthy method was copied and used in six different areas of the app. This is an obvious opportunity for code reuse. By consolidating all of these instances of the same method into the category, I was able to strip out 1,500 lines of code from the other classes.
Remember — Don't Repeat Yourself. If you can consolidate your code into a centralized location, do so. This reduces problems of having to modify all instances of duplicate code with the added bonus of reducing the amount of code.
Designing UI: Interface Builder vs. Programmatically
Years ago I wrote an FTP client in Java. Constructing the interface was an arduous task of making a small edit, compiling, running, and then repeating the whole process over again. Fine tuning the look and feel of the application was not a quick process.
Enter Interface Builder and Project Builder (the precursor to Xcode). It was immediately apparent that Interface Builder was a godsend of a tool. I could rapidly prototype new UI designs with the drag and drop interface. No more endless edit-build-run cycles! Improvements in programming languages and their associated tools are often incremental, but Interface Builder was one of those rare massive jumps in programming productivity.
I love the visual aspect and designing beautiful interfaces, whether it is for the web, desktop, or mobile software. One of the things I love about macOS (née Mac OS X) is the beautiful interface laid on top of a UNIX core. It's a world of both beauty and brawn. So it is not a surprise that I enjoy creating interfaces using Interface Builder.
I was once knocked out of consideration for a programming job because I preferred to design my UI in Interface Builder instead of doing everything in code. Perhaps that company felt it was easier to review UI changes if they were in code or to avoid the horrendous storyboard conflicts which easily arrise when more than one person works on the same project. I get that, but I'm not so certain that this is ultimately a worthy tradeoff.
The same program mentioned earlier had been originally designed without any storyboards or XIBs. This means that all of the UI is set up in code, which takes up a sizable portion of each ViewController to configure the UI elements. When separating the view and the controller, it is perhaps best to design the UI in the tool which was intended for it.
If you are purposefully designing all of your UI programmatically inside your view controllers, there is a special place in hell for masochists like you. If designing UI programmatically is your thing and you can do it quickly and effectively, then knock yourself out. Just keep in mind that other programmers may have to maintain your code someday. Designing UI in code is like the adage I heard when I was first learning C: Just because you can, doesn't mean you should.
This is not to say that there isn't a time and place for designing certain UI elements in code. Interface Builder is easy and powerful, but it is not all inclusive with everything which can be done. If you want to perform more complex UI operations, such as a wavy border or rotating a view to a specific angle, that will require the aid of code.
However, designing all of your UI elements in code takes both space and time to generate. In the effort to reduce unnecessary code bloat, use storyboards and XIBs as much as possible, and reserve the more complex effects to code. To extend the capabilities even further in Interface Builder, make use of IBInspectable and IBDesignable to add custom controls for your UI elements, such as buttons and views.
In Ryan Poolos' 360iDev presentation Life Beyond Storyboards: Building Your UI In Code, he shows how it is possible to design an iOS app without the aid of storyboards, but he does not propose an effective reason why someone would want to do this fulltime. He talks about the How, but not the Why. This echoes a line from the novel 1984: I understand HOW: I do not understand WHY.
Auto Layout certainly has its benefits, especially when dealing with variable size devices, but what it makes up in flexibility it sacrifices in brevity compared to the old method of using CGRect
s to size and place views. What might have been a single line of code can easily quadruple (or more) in size by implementing Auto Layout constraints. Whether or not if you like Auto Layout, it's the direction Apple has been taking for years, and it will only continue as the variety of device sizes continues to expand. Fortunately, most of the complexity of setting up the interface is easily handled by Interface Builder.
While I espouse the use of storyboards, they can also be abused in a similar manner where too much is dumped into one file, resulting in their own "massive" problem. I've worked on some projects where every view was thrown into a single storyboard, which could quickly bring Xcode to its knees when trying to open the file or make any type of modifications. Much as with code, storyboards need to be divided into logical sections so no one storyboard is trying to do too much. Storyboards can be finicky and are a nightmare to resolve when doing merge conflicts, so it is best if storyboards are kept small enough that no more than one developer needs to actively work on any one storyboard at a time.
Conclusion
None of these approaches need to be all of nothing. Use the best tool for the job. Reuse code so you aren't unnecessarily repeating yourself. Just keep in mind that the best code is no code at all. The less code there is, the less there is to maintain, and the less chance there is for bugs. By maintaining good organization and programming practices, you should be able to keep the size of your ViewControllers to a manageable size.