iOS View Code — A Comparison with Interface Builder

Raíssa Nucci
Movile Tech
Published in
12 min readMay 5, 2020

[Thanks to my cowriter Rodrigo Maximo]

Introduction

This is the first of a series of two articles in which we are going to discuss two different ways for designing iOS views and screens: Interface Builder’s Storyboards and Xibs, and plain old view coding.

By no means we are forgetting about SwiftUI, the new Swift-only Apple framework, which gives us the experience of view coding and interface builder both at the same time, and has advantages and disadvantages of it’s own. But getting into those is not this article’s purpose.

Pros and Cons of both approaches will be presented along with some considerations over the subject. On the next article of this series, we are going to present some examples and personal experiences to make our points clearer and help those who are new to View Code.

Finally, we are going to overview the main points discussed, and why, nowadays, we tend to choose view coding for designing iOS apps over Xibs and Storyboards.

Some definitions

First, let’s put everyone on the same page about the key words we are going to mention in this article.

  • Interface Builder is an editor within Xcode which makes it simple to design a full user interface without writing any code.
  • Storyboard is a visual representation of the user interface of an iOS application, showing screens of content (view controllers and its views) and the connections/transitions between those screens.
  • A xib file correspond to a view element and can also be laid out in the Interface Builder, allowing developers to create and manipulate user interfaces graphically instead of programmatically.
  • View Coding as the name might suggest refers to designing view elements without the visual tools of Interface Builder, doing so programmatically, so writing code.

Preferring Storyboard

Easier to learn

We believe most iOS developers might have worked on at least one project with Storyboards and Xibs, since it is probably one of the first things learned about iOS.

This is probably how most of us learned how to build our first screens and oh, wasn’t that a thrill? Being able to just drag some elements around and have a working screen flow.

That’s is definitely one of the main features when anyone thinks of Storyboards: how easy it is to learn and make something functional. This is mainly due to the its visual aspect.

Hearing about constraint setup programmatically may cause shivers on some developers. Yes, it can be verbose and even a bit boring, what definitely would demand more time to be implemented, and of course the learning curve is also slower, specially for beginner developers.

Better for Prototyping

Storyboard are meant to be what the name suggests: a board that tells a story. That means their purpose is to allow us to design our views and view controllers and connect them in a meaningful way that tells the story of our iOS app. When we create these connections, storyboard takes care of the transitions between screens. That’s one of the reasons why they are so great for prototyping: with barely any code it’s possible to have screens designed and navigating through each other.

Real time visual feedback on Interface Builder

This is precisely where view coding falls behind Interface Builder approaches. View Coding configures it self by designing views and layouts using solely code. Therefore, one has to programmatically create and position views and components, using Auto Layout APIs to do so, without any visual feedback whatsoever on how the layout will look once the app is running. This may seem like a huge downside of building views programmatically. One may think each iteration shall take an eternity, once you need to run the app every time a visual alteration is made, what may be another negative point about View Code.

Easier when dealing with size classes

Also, storyboards are super handy when it comes to designing apps for multiple screen sizes and orientations. For layout adaptability we use Auto Layout, through which rules (constraints) are defined to govern the content of the layout. It automatically readjusts layouts according to the specified constraints when certain environmental variations (known as traits) are detected. Auto Layout can be used regardless the means chosen to design app views, however, storyboards make it fairly easy to configure layouts for different screen sizes, via Size Classes, traits that are automatically assigned to content areas based on their size.

Nevertheless, besides all the goodies storyboards can bring in some circumstances, they can also be become an utter pain in many situations.

Preferring View Code

Easier to separate views in different files

A fairly common mistake developers make on their projects is to have a single Storyboard to tell the story of their whole application. That might work for small projects, but as projects get bigger and more complex, this single storyboard becomes a nightmare because of the quantity of screens.

Files render and open much faster

Also, depending on the size of this little monster, the file can take plenty of time to be opened on Xcode, if it doesn’t cause it to crash. The right way to handle this would be to use Storyboard References, and breaking the app into multiple storyboard files. But even though, depending on how long the flow is, its storyboard file may still be a heavy one. However, using View Code allows us to create multiple files and classes and separate them as much as possible. So, Xcode will not complain about opening each one of those files. Besides, despite the fact we have to run the app every time we’d like to see visual changes of view code implementations, if we take into consideration that the app will be lighter and faster to build without all the overhead of storyboards and xibs, in the end you may even find it is faster than Interface Builder real time rendering.

Componentization

This possibility of separation of concerns allows us to have great capacity of reusability and componentization. We can create view component and build more complex views by composition or even inheritance. As we are working with plain code, every technique we have for system componentization and reusability can be used with our views. This allows us to better organize, separate concerns and have purpose clarity for each file and view.

While storyboards don’t offer anything regarding view reusability (if you have a round button that is used throughout the whole app and you are using only storyboard, be prepared to redesign that button on every single screen), a certain level of componentization can also be achieved by using xibs. Since each xib file is supposed to represent a single view, component views can be created on their own xib files and afterwards used to compose other xib views or even storyboard views. That way, instead of having to go over every label on every storyboard if the app’s color palette changes, we could go straight to our custom label component and change that color and, voillá, may all the labels be changed. But, despite the possibility of composing with xibs, we can’t say the same about inheritance.

Yes, inheritance can be done with xibs, but it can get quite messy. Suppose you have a view A inheriting from view B. Problems start once you can only inherit from this xibs File owner — a.k.a. its code implementation. That means all the layout has to be re-built on two different xibs files and IBOutlets need to be re-linked (you would have too labels linked to the same outlet). The mess continues once changes need to be made to B view, for example. Imagine you add an extra label to it and create its outlet on view B file and so on. Xcode won’t give any warning that you also need to add that new label to view A xib file and link it to the new outlet. For your surprise, when running the app, all instances of view B will work just fine, but when trying to instantiate view A, your app will crash. And, specially if you are new to the project, these crashes can be pretty darn hard to identify.

Reusability and Centralize common features

Related to what was said above, and also another advantage of View Code in terms of reusability is the possibility to have a property to centralize a common characteristic for a view. For example, if we have a three labels that should have the same color, in the xib or storyboard we have to set the color for each one. Then, if this color should be changed, we have to change for the three labels, while with View Code we could have a property for this color, and attribute it for each label. Of course this could be done using xibs, just by adding this same property to its file owner swift class. But that brings us to another very important point when thinking of using Interface Builder: code always wins, in a sense that, in the end, despite of what you do on storyboards or xibs, if there is code overriding this behavior, what was defined on code will prevail. When you don’t have everything centralized on code, finding out why something set on Interface Builder is not reflecting how expected in the app can be a great source of headaches.

Animations and Content Based Layouts

There are also some things that can only be done through code. One such example are animations. Sure, IBDesignable and IBInspectable (attributes used by Interface Builder used to render elements directly in Interface Builder) can be used, but still we would have to implement the animation on code. Complex layouts that greatly depend on the content being presented (dynamic content fetch from server for example) are much easily implemented using view code. That’s because you will only have the info needed for display on run time, therefore, only on the swift class of the view. Based on that content, constraints will need to be changed, views added or hidden, colors set and etc. Even if you had a xib file defining basic layout for that view, its behavior would mostly be overwritten when running the app by the code underneath handling the content.

Merge and Review

Another point that can be really annoying with storyboards and xibs, specially if the project contains all the screens in a single Storyboard file, is working with other developers and having to deal with merge conflicts and pull request reviews. Since a storyboard or a xib file are basically autogenerated XML files, it’s really hard to accomplish these two things. Imagine you’re going to review a Pull Request that has some storyboard changes. How do you know what was changed and if these changes achieve their goals? (specially taking into consideration that Xcode generates changes on these files simply by opening them) You probably don’t. Meanwhile, when using View Code those problems don’t happen. Code is semantic, code has meaning. Every line of code changed has a clear purpose that anyone working on the project should understand, making reviews more meaningful and accurate.

Even though constraints API may not be the best (although iOS 11 and forth APIs are pretty decent), it is still code and therefore it has meaning and semantics to developers. When setting constraints on code the depth of knowledge acquired on how Auto Layout works is remarkable. It can get us really knowing our views, their hierarchy, how they are related trough constraints. And it’s guaranteed that you’ll finally learn what the hell compression resistance and content hugging priorities are for!

Regarding verbosity, there are many 3rd party libraries out there to help with auto layout API’s readability. Cartography, SnapKit and PureLayout are just some examples. Using any of these 3rd parties or even newly Auto Layout APIs will sure make your constraints pretty understandable and maintainable.

Unit Tests

Besides, a really terrible problem that storyboards generates is the impossibility of testing UIView and also UIViewController properties without opening the view properties access levels. This happens simply because when using storyboard, we don’t have the control during the view initialization. So, all its properties can be only referenced by outlets, and so they can’t be injected by dependency injection. This means the unique way to test them is making those properties not private. This is awful because leaves the code open to undesirable modifications, which can cause lots of side effects. However, using View Code, we can inject all the view properties by creating a custom init for the UI element (UIViewController, UIView, UITableViewCell, etc), what really makes unit tests easier and guarantees the right access levels..

Data Flow

Still talking about the lack of initialization control Storyboards and xibs bring, it’s possible to perceive another disadvantages compared to View Code, since it’s harder to pass data between two UIViewController’s because of that. This happens because when we don’t create the UIViewControllers by code, and we allow Storyboards do this job for us, we can’t inject the properties we’d like in it. Doing this, a possible way to pass the data is through a segue, and this will bring us another problem, because we’re going to have an optional property in the final UIViewController, that is also not private. So, unnecessary safe guards and other optional unwrapping code will be needed for a property that in practice will never be nil.

Safety

View Code is also safer than Storyboards . By safer we mean that it is less prone to crashes. This is true because there are lots of identifiers we set in Storyboard, that will make our code to compile, but can cause some crash. Also, for example if we delete some outlet or action code, and we forget to delete the storyboard reference for this outlet, the code will compile successfully, but the app is going to crash when accessing that scene.

Localization

In addition, something that is really easier when talking about View Code is localization. Implementing this in storyboards and xibs implies in having one different file for each new wanted localization, which may be terrible, since changes in the UI would have to be done in each file. However, there is a better way to localize a storyboard/xib, that is through the localization pane in File Inspector. This will create a new strings file for each localization, what solves this previous problem. Nevertheless, we still have a problem here, since the created strings file has each localized string defined by an id, which is automatically generated by Xcode, and it’s not something really readable. This is going to difficult our lives in a file with a lot of localized strings when some changes are needed.

Obviously, we can overcome this problem by replacing them by View Code files, but we could also just attribute the NSLocalizedString’s in .swift files related to the storyboard/xib we want to localize, instead of using the File Inspector “trick” mentioned above.

Summing Up

In order to overview everything we discussed in this article, a list with every single advantage of each approach will be shown below.

Storyboard

  • Easy to learn and create things that work
  • Better for prototyping
  • Easier when dealing with size classes
  • Real time visual feedback on Interface Builder

View Code

  • Easier to separate views in different files
  • Files render and open much faster than storyboard and xib files
  • It is possible to Inherit and Compound Views
  • We can take advantage from reusability and also centralize common features
  • Much easier merge and review since files are code and not a unreadable XML’s
  • Unit tests are easy to implement and they aren’t necessary to be built in a poor way, breaking the access level of properties
  • Easier data flow between screens
  • Safer — no more unsafe functionalities in storyboards and xibs (crashes instead of build time errors)
  • Localization is easier
  • Animations are only possible to be implemented by code

Conclusion

Our intention is to share some knowledge and experience we both have using these two approaches for developing interfaces in iOS, and the main purpose here is not to convince the reader which one is better, but just to shed some light into each approach advantages and disadvantages. This does not mean there is always a better solution, but maybe a more suitable solution for your context and situation.

Briefly, if we had to create a new project, with the purpose to be a large and scalable application, with a lot of users and with a lot of developers working on this, we would probably opt for View Code, due to merge and review facilities, compilation and rendering files time, unit tests, reusability and the possibility to centralize behaviors, composition and inheritance, and finally the safer environment (avoiding unexpected crashes).

However, if for example we had to teach students or iOS beginners about auto layout and how to create some views, we might prefer storyboards.

To make all the arguments presented here more clear and relatable, the next article of this series will bring real life examples of how to build views using view code, how to better organize it and some tips and tricks to make the project even more readable and maintainable, and, hopefully, faster to build.

--

--