Storyboards versus XIBs versus custom code.
One of the most passionate topics among iOS developers is "How to create the application user interface?" We have two different groups: the first are those who love creating a GUI in the Interface Builder, and then those who hate it and prefer doing it through code. I read a lot of posts, and tried different things, and my conclusion is that there is no silver bullet, because each of the approaches has its own pros and cons. The goal of this article is to help you make the best choice for your project.
There are generally three ways to create a user interface in iOS:
- Storyboards - this is a visual tool for laying out multiple application views and the transitions between them (segues).
XIBs (or NIBs) - each XIB file corresponds to a single view element and can be laid out in the Interface Builder, making it a visual tool as well. Just note that the name "XIB" is derived from the file extension (previously
- Custom code - no GUI tools are used, but rather, all custom positioning, animation, creation, etc. is handled programmatically.
I will not describe them here in detail since there are plenty of good online guides about this. Rather, I want to focus on the pros and cons of these approaches, and elaborate on when it is appropriate to use each of them.
Storyboards are the latest addition to the iOS UI toolkit. They are announced as a revolution, and replacement for XIBs and custom code UIs. And storyboards are definitely a useful tool - but not so much a replacement, as much as they are a complement for XIBs and custom code. They are the right choice in some, but not all situations.
When I started to develop apps, I thought that storyboards are the only way to create a UI. And I like them a lot, because I could see the whole design, easily change it etc. But as an application grows, the storyboard becomes massive, slow and unreadable. And this is a fundamental mistake. Because the storyboard loses its purpose and ends up looking like this:
Applications should be divided according to logical units (stories) and each of them should have their own storyboard. As its name implies, it is a board with a story to tell. It shouldn't be used to mix unrelated stories into one big volume. For example, a list of players and related functionality (adding, rating, etc.) can be one example of logical unit. Then you can see the benefit of using storyboards:
When to use storyboards?
When you want to see some flow without building the app, a storyboard is the best option. Also if you create static table views or more then one cell template, you can use a storyboard. Finally, they can help when you want to reduce the amount of code, because you don't need to write the code for allocation and initialisation, as views are automatically allocated.
The main advantage of using a storyboard is its visualization. Anyone who takes a look at it can see the relationship that the screens have with each other and what the application flow is. Another advantage is rapid prototyping, because you can mock up the design, navigation flow and transitions of an application without writing much code.
Additionally, it's much easier to use auto layout if you create your UI using storyboards or NIBs.
This might lead you to believe that a storyboard is the perfect solution - however, there are also downsides to this approach.
The first disadvantage is reusability. Storyboards are very limited when you need to copy or move code, especially graphic elements, because you need to move all of its dependencies. Also, if you work with other developers on the same project, you will run into issues, because everyone's modifying the same file (leading to merge conflicts). A storyboard file is specific and resolving conflicts can be very painful. Since the actual interface "code" generated by the Interface Builder is non-readable XML (some would argue that this is a pleonasm, but bear with me), it can be nearly impossible to fix even the smallest merge conflict in a massive storyboard file. This could lead to massive amounts of work being lost or corrupted - which is not very cool.
Sometimes data needs to be passed between view controllers, and because we use segues for transitions, we will end up with the giant
prepareForSegue() method with many if/else statements. Storyboards take care of handling the flow between view controllers, but not the flow of data.
Some people have also experienced bugs in Xcode with the usage of storyboards - eg. having to frequently flush the
DerivedData folder because of inconsistencies.
This is the "old-school way", which doesn't mean it's bad or deprecated. It represents only one specific view element (view, controller, table cell, etc.) - in other words, every view has its own
.xib file. The advantage of this approach is that each component is easier to develop, easier to test, and easier to debug.
When to use XIBs?
We can use them for modal views, login/register screens, reusable views (like templates, table cells, etc), basically everywhere. But for complicated view with dynamic content, try to avoid them.
One of the main advantage is reusability. Other words, "prepare once use everywhere". You can use the same layout in multiple classes. This can be very useful and can save development time.
Another advantage is that, like with storyboards, the visual tool helps you see what are you making. You can also easily use the auto layout option.
Similar to the problem with storyboards, working with other developers on the same XIB can produce a lot of conflicts. Additionally, highly dynamic views are impossible to describe as a XIB. One more disadvantage is harder debugging. For example, if you forget to make a connection in the Interface Builder, or delete something, or add the wrong one, etc.
One thing to be aware of when working with XIBs: they are lazily loaded, so they don't use memory until they have to. While this can be an advantage, there's also a latency due to the lazy loading process, making it something of a downside as well.
Custom code, or, handling UI programmatically
Sometimes storyboards/XIBs and the Interface Builder aren't enough. When we use code for creating a UI, we can understand what's under the hood. At the beginning we need to know that any UI that can be done with storyboards and XIBs can be implemented also with raw code. This is the last option and rescue. It has a lot of pros, but there is also some cons which are not negligible.
When to use custom code?
We need to use this approach when we create dynamic layouts, or when the layout has to be customazible and include some effects (shadows, borders, rounded edges, etc). Sometimes it's the only solution.
Custom code pros
There are a lot of benefits to using raw code for creating a UI. The first advantage is performance. Storyboards and XIBs need to be translated to code at the end. So you can skip that step and get a faster build time. Also you get more control over layout and you can easily customize elements. For example, if you want to change a color or font size/style in the application, you can simply edit it in one place, and the change will be reflected everywhere. It's also easier to debug when some error occurs. Another advantage is reusability - if an application uses a set of elements that look the same across the application, you can create them in one place, and then use them across the whole app. For example, text fields, buttons, labels, etc. Also, resolving merge conflicts is much much easier if you use code. This is a major advantage when you work in a big team on a big project.
So once again we can think that raw code is the perfect solution for creating a UI. However, there are also cons that shouldn't be neglected.
Custom code cons
We will start with prototyping. It's difficult to imagine (visualize) how a layout looks until you see it on screen. This means that you need to have a lot of iterate/run/debug cycles, which can be very annoying. You need to rebuild the whole app in order to see even a tiny change. So the second disadvantage is that layout changes can't be applied that fast. Also the layout can't be implemented so easily. You need to add all constraints for your element programmatically. For example this is one constraint (ObjC):
[NSLayoutConstraint constraintWithItem:self.button1 attribute: NSLayoutAttributeRight relatedBy: NSLayoutRelationEqual toItem: self.button2 attribute: NSLayoutAttributedLeft multiplier:1.0 constant: -12.0];
Finally, if you receive a new project where all the UI is made in code, it takes much more time to understand how things work, and to ultimately start working with the code to change something.
Although all approaches are different and each one has pros and cons, if you are familiar with them and use them together in projects, you can save your time, nerves and at the same time build great apps. So, we can be very happy that we have different tools for building UIs. With code you can do everything that's possible, and with the other two you can see the flow and basic design of the app more easily. The conclusion then, as with many other things in programming, is to analyze your specific requirements in advance, and make a decision about which approach will make most sense for the project you are working on, and go with that.