The Best of Everything
Or how to get the best of Interface Builder in code
There are two main ways of building native user interfaces for iOS — visual (using Xcode Interface Builder) and programmatic (with code). In my post, I’d like to turn the spotlight to the problem of two concerns (construction and usage) being mixed¹ out-of-the-box in the process of creating user interfaces with code and highlight my — inspired by the Interface Builder — way of dealing with it.
First, let’s take a look at both approaches in practice. Let’s consider some very basic UI:
The UI consists of four things:
UILabelwith a placeholder text
UITextFieldthat we want to make accessible to the view controller (to be able to read it’s
UIButtonthat we don’t have to manage at the view controller level, but we want to handle a tap action related to it
UIStackViewthat keeps all of the above together in a vertical layout, also without a necessity to be directly managed by a view controller
The functionality is dead-simple — whenever a user taps button we take a
text from the text field and
The implementation of related
ViewControllers looks like this:
There is a significant difference in the volume of code that you have to write up there and the best code is no code at all², but that’s not the main issue. There are valid reasons to write user interfaces in code³ (reusability, ability to develop in parallel) and accept it’s intrinsic downsides.
What I really appreciate about the implementation on the left side is the clarity. It is super clean and focused solely on the usage while leaving the construction responsibility to the default implementation of the
Given that the separation mentioned above is not available out-of-the-box when implementing user interfaces in code, is there a practical way to avoid this outcome? The answer is yes, even more — Good Programming Is Like Good Writing⁵ and there is no single “right” way to write any implementation and there is a number of possible solutions:
“The other part of it is also having a grand or free mode of expression that there are many different ways that you can say something” — David Heinemeier Hansson
Mimicking the Interface Builder in Code
To mimic the Interface Builder in the code I tend to focus on keeping all the construction logic in a separate file (as it goes with
.storyboard or a
.xib) and expose to the view controller only what matters. Also, I prefer to keep that logic in a nested class to not clutter the namespace of the view controller with
There is a couple of rules out there:
- non-interactive, placeholder views and controls (e.g our
stackView) are built using functions with
privateaccess level and are entirely not exposed to the view controller
- interactive views that we want to manage in a view controller, as well as instances of the views offering actions that have to be handled by a view controller, have to be built outside of the main
buildViewmethod and injected into it
The comparison of view controller implementations looks a bit better now:
As I‘ve written before — there is no golden rule. That’s how I do it and if you like it feel free to adapt it to your project. What matters the most is consistency and my approach affords it across multiple cases.
When it comes to the granularity of our nested
Builder class we may want to integrate
buildSomethingLabel methods depending on the complexity of our views (creating a subclass of the
UIView is another option).
static nature of the
Builder may also be not sufficient for all cases — if your view is more dynamic or customizable you can consider leveraging dependency injection here and leverage non-
This approach lets us keep the minimal footprint of the UI construction code in the view controller. Having a view controller that is focused on the usage instead of both usage and construction makes us more certain that we can avoid a Massive View Controller problem⁶. In most cases, it allows you to remove tens or hundreds of lines of code from it.
You can find the related source code here.
I’m Maciek Czarnik
iOS Developer, musician, maker. Passionate about building beautiful, robust, useful and user-friendly apps. Contact firstname.lastname@example.org for project inquiries.