Storyboard & Xib

by Chris Ching

design

iOS developers have powerful tools to build apps. The most important one is Xcode, the main application of the software development kit that Apple has. Inside Xcode, there is a visual editor called “Interface Builder” that allow developers to create, configure and setup views in a user-friendly visual way (instead of just writing code).

In this post we are going to analyze the pros and cons of using this Interface Builder tool and which are the best practices used at Mobile Jazz when using it. Also, we are going to link to some third-party libraries that we use in order to speed up and improve our development efficiency, as well as our final product quality.

The Basics

XIB

XIBs are XML files that define and configure a set of objects, and are designed specially to manipulate mostly views (subclasses of UIView). Xcode has a user-friendly editor that can display those views as it were a running app, making it extremely easy to configure and design the layout (saving lots of lines of code) .

Even if most developers associate an XIB file to a “screen” or a “view controller”, XIBs are generic containers of objects and can be used together with other object types as UIViews, NSObjects or just alone.

Storyboard

A Storyboard is an XML file representing the unification of a set of XIBs in order to define the navigation between of a group of view controllers. With an Storyboard a developer can define multiple “screens” (or UIViewController subclasses) and the navigation between them.

As a difference of a XIB, Storyboards are made to define UIViewController’s views and navigation between them.

Pros & Cons

Lets assume now that our readers have already a basic knowledge of what and how to use XIBs, storyboards and even do it by code.

In the following bullet-points we are going to list some benefits and inconveniences (that you may have probably discovered by yourself) of XIBs, storyboards and code:

Benefits of XIBs vs Code

  • Visual configuration of views.
  • Visual configuration of auto-layouts.
  • Visual configuration of size classes.
  • Saving time & code while “creating instances”.
  • Saving time & code while “configuring objects”.
  • Fast UITableViewCell prototyping.
  • Fast configuration of control actions (IBActions).

Benefits of Storyboard vs XIBs

  • Can prototype UITableViewCells directly inside the Storyboard itself.
  • Can define static UITableView sections and rows.
  • Can use auto-layout to add constraints to the topLayoutGuide and bottomLayoutGuide.
  • Can specify navigation and transitions (that’s one of the main purpose!).
  • Can define multiple “screens” (UIViewControllers) in a single place (no need of multiple XIBs).

Inconveniences of XIBs vs Code

  • Easily breakable when merging (Git).
  • Cannot define complex auto-layouts.
  • Cannot reference (or include) other XIBs.

Inconveniences of Storyboards vs Code & XIBs

  • Storyboard are large files: slow to load sometimes.
  • Requires a big screen to display all (or even partial) content.
  • Easily breakable when merging (Git) .
  • High probability to break it when merging (Git) as Storyboards contains lot of information.
  • Lots of warnings when supporting iOS 7 and iOS 8 (margins, size classes).
  • Cannot reference (or include) other XIBs.

Best Practices

One of the most important problems we face at Mobile Jazz and that we need to resolve extremely well is how to create good app architectures, considering that projects needs to be usable, scalable and well organized. Making good usage of Storyboards and XIBs helps a lot in all these.

First of all, we need to think in terms of “how is the app to be developed”. Is it big? Does it contains lots of screens? or it is a small-medium app with a relative small group of screens? Depending on this, we may take one approach or another:

  • Small apps: use storyboards without hesitating and include all your screens there. Development time will be much shorter and you will have a visual insight of the whole app in a single place, which may be very helpful in terms of organization.
  • Medium apps: use storyboards for the main navigation. Additionally, define in independent XIBs those screens (view controllers) that are going to be used repeatedly or need a specific configuration.
  • Big apps: Here the trick is to split the app in as many independent modules as possible. Use multiple storyboards, one per each module and also use independent XIBs for those view controllers that are used everywhere (in more than one module) or require specific configuration.

However, there are other points to consider. For example, the usage of independent XIBs to specify views (not view controllers) that are being used in multiple screens. A clear example of this is when prototyping UITableViewCell subclasses, as we have create a XIB for each cell class (this can also be done inside a Storyboard).

The same approach can be done in other views. However, it will be needed an specific “initializer” for the view from the XIB, as we cannot use the usual “-initWithFrame:”, as here we will need to instantiate the XIB (UINib) and retrieve the views and objects from it.

A good example on how this could be done is reproducing the same behavior that UIViewController has with the method “-initWithNibName:bundle:” in UIView in a category. This method would initialize a UIView from the instance created from a XIB.

Using this approach, we can now define and configure views (with its subviews) inside XIB files and create instances from them in a very easy and straightforward way. However, this approach has an issue: we cannot instantiate views that are defined in a XIB file from another XIB file. In Mobile Jazz we have faced this issue and proposed a solution: the NibWrapper.

Nib Wrapper

The NibWrapper is a UIView that can easily insert as a subview another view that has been specified in a XIB file. The benefit of this is that in as many XIB files we want, we can use a NibWrapper view to insert another view that has been defined in a different XIB.

NibWrapper

This solution is very useful to reuse some generic views in multiple view controllers.

However, if your have to create a custom view with a specific behaviour, you can always create it by manually laying out the subviews by overriding the method “-layoutSubviews”.

Multiple Storyboards

As mentioned before, one option is to divide your app in multiple modules and create several Storyboards. This allows your app to properly organize your code as well as establish some “entry points” to each module by considering the “initial view controller” of each storyboard the first screen to show on that module.

To help manage this, one good option is to create a category on UIStoryboard and return different initial view controllers.

Subclassing objects to be used in XIBs and Storyboards

When creating subclasses of UIView, it is important the think that that view can be instantiated in both programmatically and inside a XIB. Therefore, do not forget to make your subclass easy configurable via a XIB:

  • Add the “IBOutlet” flags to your delegate, data sources or any other property that may be assignable to the any other object.
  • Use “IBInspectable” to each configurable property. This enables Interface Builder to configure the object in an XIB file.
  • When possible, use the “IB_DESIGNABLE” flag in your view class to do a live rendering of your view inside Interface Builder. Also, using the macro “TARGET_INTERFACE_BUILDER”, it is possible to separate between code being executed in runtime or code being executed by interface builder. This way, it can be done an specific customization of the view state while being rendered inside an XIB.
  • As the XIB will instantiate your view using “-initWithCoder:”, make the view “mutable-enough”, so it can be configured without needing to use the default init method.
  • Override and use both “-initWithCoder:” and “-initWithFrame:”.
  • Use “awakeFromNib” to put code that rely in other XIB objects (IBOutlets and others). When this method is called it is guaranteed to have all its outlet and action connections already established.

Also, it is important to prepare your UIViewController subclasses when using them together with XIB files:

  • Use IBOutlet to refer to your XIB views and objects (views contained in the main controller view with a weak reference).
  • Use IBOutletCollection (with a strong reference) to handle sets of objects from your views. Example: to translate a set of labels or to configure a set of buttons.
  • Use IBAction to receive actions from controls.
  • Remember, XIB elements, as well as any views, are only available once the view controller’s view is created, not before. Therefore you must initialize and configure your properties and ivars properly. Use “-initWithNibName:bundle:”, “-loadView, “-viewDidLoad”, “-viewWillLayoutSubviews”, “-viewDidLayoutSubviews”, “-viewWillApear:” and “-viewDidAppear:” to handle properly the view lifecycle.

Summary

In retrospective, we have described some approaches and practices we do at Mobile Jazz when creating and architecting an app for iOS. The key points are:

  • Decompose (decouple) code and views as much as possible.
  • Make your UIViewController subclasses modular and reusable. You might want to instantiate a view controller at any moment!
    • Use XIBs or Storyboards consequently.
  • Implement your UIView subclasses to be XIB/Storyboard-friendly.
  • UIStoryboard is a great tool, but it’s not the only tool.

Also, remember to use the view debugger to show and debug in runtime your window layout in interface builder.