The recent changes to Interface Builder made me change my mind about it. I was sold on the Preview feature which allows to test the UI on different screen sizes and in different orientations. Let’s see how to make the best use of this feature.
Using Interface Builder
There are two major things that you can do in Interface Builder to get your job done: layout and styles.
IB is great at defining the layout. It allows you to add constraints surprisingly quickly. You can (arguably) do it even faster than if you were using DSLs on top of Auto Layout like PureLayout or Carthography. I used to be a huge proponent of those tools but now I tend to rely less and less on them.
The best thing about working with constraints in IB is that it allows you to get instant feedback about any problems you might have with the constraints that you’ve defined. You can iterate very quickly without ever running or even compiling an app.
Defining styles is a different thing. The cons of defining styles in IB are:
- You can’t use predefined styles shared throughout the app
- You can’t take advantage of the tools that auto-generate styles for you (e.g. Zeplin)
- It’s tedious to work with styles in the GUI
- If you start changing any of the views’ properties in IB you end up with two places to look when you want to know their final values: both IB and code.
The pro of defining styles in IB is that you can visually see what the UI is going to look like without running an app. This is one the major reasons which make IB so appealing to me. But if we are not going to define any styles in IB how are we to actually achieve that? Fortunately, there is a very straightforward way to do that and it involves one of my favorite IB features which is
@IBDesignable enables live rendering of the custom views in Interface Builder. In order to enable live rendering of the entire View Controller UI we need to make its entire view
@IBDesignable. Simple as that.
The example in the screenshot in the begging of the article is rendered entirely by an
ActivityDetailsView class. This view contains a table view and implements its data source to render the
Activity model objects. Here’s a part of the implementation of the
ActivityDetailsView.swift file to get an idea how it might look like:
In order to feed the test data into the view the special
prepareForInterfaceBuilder method is called:
When Interface Builder instantiates a class with the IB_DESIGNABLE attribute, it calls this method to let the resulting object know that it was created at design time. You can implement this method in your designable classes and use it to configure their design-time appearance. For example, you might use the method to configure a custom text control with a default string. The system does not call this method; only Interface Builder calls it.
The only part that is left is to add this view into the view controller. We can now start testing the entire UI using IB:
IB is not just a great tool for creating the UI but it is also great for testing it. By doing so you can dramatically reduce the number of times you need to run your app during the development cycle. You can rely on IB to test your layout, styles, and even some of the logic that displays your model objects (however, you should really invest time in unit testing in order to test the correctness of the later).
The major issue with
@IBDesignableis just how unstable the Interface Builder (as of Xcode 8.3) seems to be when it is used. You should definetly check if you can tolerate it before commiting into this approach.
I hope that Apple will continue improving IB. Imagine how great it would be if Storyboards were interactive in way Playgrounds are (see
liveView. It would enable developers to do even more things with the UI without ever running their apps (e.g. test animations). In fact some teams actually replaced Interface Builder with Playgrounds.