Storyboards x Xibs x ViewCode: Which one is better?
If you are an iOS developer and is starting a huge project, some very important decision for you to make is which kind of user interface you should rely your application on. Some people think storyboards are a more suitable approach while other think designing the interface entirely with Swift Code is better. Of course in within my 5 years experience I have my preferred one, but in this article I will (or at least try to) be impartial and present to you each of the options and its pros and cons.
1) Storyboards
When I faced storyboards for the first time, right when I created my first Xcode project(maybe a Hello World?), I simply though they where totally awesome. Imagine, me, who was used to coding interfaces in Java, right in front of an IDE that allowed me to create my screens while prototyping at the same time. I just needed to drag each UI component I needed straight to my canvas and attach some coding to each one or defining some callbacks. At the same time I could customize them by playing with the Attribute Inspector. It was fascinating:
Besides, I could make an entire flow of screens within the same file and link them with the so called UISegues.
This is not so fascinating as you may think when starting to work with storyboards together with a big team… If you don't know yet, the storyboard doesn't consist on magic as it looks like. It's a XML file representing a declarative interface for your UI linking that with Swift code in your custom UIViewController classes.
For who is starting learning iOS, it's very important because you know very deeply how the viewControllers and views work and how to build your interface with concepts like callbacks, outlets. It's a very intuitive way for understanding. Imagine learning about constraints without a visual representation of them? A lot of people would give up on this topic if they began with ViewCode..
Why I don't recommend storyboards for a big team? Well, certainly you have dealt with Git and know how disgusting it is to resolve some conflicts in a file. The rule is very clear: the bigger the team and the fewer the files, the bigger the conflicts. If your team keeps a very big flow of screens in a single storyboard, prepare for the conflicts! And since not everyone can face a XML language very clearly, it will be a headache to identify which changes should be kept and which ones should be discarded(or maybe keep both).
Besides, another issue of using storyboards and any kind of interface builder is that it's very hard to solve bugs. When you have your interface built on code, it's a piece of cake to debug each line, each assignment, constraint and find where some undesirable result is reproduced. But with storyboards, everything is assigned by hand and it's very hard to identify which IBOutlet or selector is problematic. Even worst when using runtime attributes..
So, this is how I would describe a storyboard experience:
Pros:
- Improves learning curves for UIKit and Swift
- You have a visual representation of what you are coding
- Prototyping an entire feature flow
- Navigation design
Cons:
- Very hard to debug
- A bunch of conflicts when working with a big team.
- If you decide to customize storyboard components with Swift, you may not even see the results in the storyboard while defining.
2) Xibs
Xibs are an alternative solution for interface building despite the storyboards. The core difference is that, while storyboards represent a graph of screens, each one built in its singular way, and the minimal element you deal is the screen itself(the ViewController), the Xib's core is a single representation of a View.
It may be any visual component, like a button, a label, a custom view or a cell. It doesn't matter, but the core advantage above the storyboard is the isolation principle: the Xib represents a single UI context, while the storyboard may contain multiple screens and different contexts. As a xib is something smaller and more cohesive than a storyboard, it decreases the probability of a conflict.
When you organize your project into scenes, which are a logical/visual unities inside your app(a screen or a component), much less people shall work in a single one and so it's far easier to keep in the long term. It's valid to remember that a Xib, like a storyboard is also a XML file:
Another fact about interface builders is that they are very hard to keep track in the long term. In my company, for instance, there was a change I needed to do in a very old screen made for instant transfers, where the only viable solution was to insert some former components into a stack view and add a new toolbar inside that. There were a lot built in constraints that I needed to remove and reapply in the new hierarchy in order to get the same previous result! It was massive even though I needed to control which interface should be presented, so it became a complex logic defining which components were valid or not and how should they be presented:
Pros:
- You still can see your own interface while defining it and different from storyboards, you place content inside fewer files and has isolation
- You can not only create a whole screen but also prototype smaller components, like views and buttons
Cons:
- Although you might have less conflicts since there is less content for fewer people, if more people edit this file, it's hard to identify and solve conflicts in the declarative language
- If you build your components entirely inside the xib, solving a bug is still hard.
- Hard to change in the long term if the interface hierarchy becomes too complex and you need to insert some new UI within all those predefined constraints(imagine the puzzle it is..not every time you can see which constraints can be removed or not in order to avoid ambiguities)
3) View Code
Now it's my favorite part: building the interface in a totally imperative way and knowing exactly how it's build piece by piece in Swift and defining behaviors.
Of course View Code scares a lot of people because you don't have the comfort to see the outcomes of what you are creating. But I can guarantee to you: Prioritizing to create your interface with code makes you a much more mature developer and allows you to achieve a very deeper acknowledge on the UIKit framework.
It's not hard to build a whole screen(ViewController) with code, but there are only some small details you should keep in mind. The order of steps to build an interface is predefined, which means, you cannot define constraints between components at all before establishing a hierarchy, and you must do it by hand, differently from the interface builder, where you do that in the moment you drag a UI component into your scene. A hierarchy as you know is the tree speaking which view is inside the other and which are the simblings. If you don't establish a hierarchy, when you try to create a relationship between two views you will get this crash error:
This happened because you tried to define constraints between the view and its parent without even having a parent view.
If you choose to develop your interface through code, you need to follow this simple pipeline:
With ViewCode you may also debug and find which part of the UI is causing some bug:
A very good way of keeping track of your interface outcomes with ViewCode is creating a sample project defining a list of all your components(a main ViewController with a tableView, one cell per component/state) and a ViewController for each one showing each component you create and its states. For that, try grouping each small piece of reusable interface into a single class. If you create a complex View type not dividing it into smaller pieces, the chance of bugs and duplicated code is considerable.
If you want to learn more about good practices with ViewCode, check this other article.
Pros:
- You really learn a lot about how the UIKit types work
- Easy to debug with break points
- Simpler solution to identify bugs and identify outcomes reasons
- Fewer conflicts, mainly if you adopt SOLID principles in your code
- Easier to divide your interface into smaller components
Cons:
- Hard for newcomers
- If your component is too simple, almost trivial, you might need to right more code than you actually need.
- You need to keep track of a pipeline in order to avoid crash errors
- Writing constraints is not too simple and spends more lines of code than you may want..(SnapKit solves this problem)
4) SwiftUI(Extra)
It's also a great solution and if I started a whole new project I would try this one. It's awesome because you may write your interface with Swift code in a totally declarative way, therefore combining both advantages from interface builders(Storyboards and xibs) and ViewCode.
It's easy to debug since you are using Swift and also, you can check your interface at coding time through the so called Preview:
With the previews, you can run your custom View as your app consisted only of that, despite the other screens and the context it is inserted. You may not only create an entire screen but also represent your isolated components in a device simulator.
SwiftUI is easier to read, debug and you can represent some procedures that used to spend plenty lines of code in UIKit(like animations) within just a few ones.
I confess I started recently to study SwiftUI, but as I go deeper, I will post more articles with important features regarding this framework.
Pros:
- (Very) easy to debug
- You can instantly check your changes on the interface through previews
- Simple to code and divide your interface into smaller components
- No need for constraints
- Fewer lines of code
Cons:
- You need to get used to the declarative way of thinking
- Some Swift features are not too reliable when using a declarative interface(Ex: guard let else)
- You don't have the benefit of delegation between components in order to update answering to user event(despite SwiftUI provides some reliable solutions like Combine)
- Very recent and so, just few companies are adopting it
Conclusion
If you are still learning about the Swift programming language and how UIKit works, using interface builders(Storyboards and Xibs) is totally good since you may check how your interface is being constructed step by step. But if you are working with many people, using code always increases maintenance in the long term and gives you much more control over your interface. I really hope this article clarified your vision about user interfaces and gave you good approaches about how to structure it. See you in the next one ;)