In this tutorial, I want to show you some of the new Interface Builder in Xcode 7 features that I believe will change how you think about Storyboards.

IBOutlets are Strong

Apple has done some optimization in both Xib and Storyboard files. And because of this optimization, you can now define an IBOutlet as strong , instead of weak . Apple pointed this out at the last WWDC, so let’s give a look at this in more details. You can find in the documentation the chapter Managing the Lifetimes of Objects from Nib Files:

Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create should therefore typically be weak, because: Outlets that you create to subviews of a view controller’s view or a window controller’s window, for example, are arbitrary references between objects that do not imply ownership.

The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).

As explained in this paragraph, the outlets to subviews of the view controller’s view can be weak , because these subviews are already owned by the top-level object of the nib file. However, when an Outlet is defined as a weak pointer and the pointer is set, ARC calls the runtime function:

1 id objc_storeWeak ( id * object , id value ) ;

This adds the pointer ( object ) to a table using the object value as a key. This table is referred to as the weak table. ARC uses this table to store all the weak pointers of your application. Now, when the object value is deallocated, ARC will iterate over the weak table and set the weak reference to nil. Alternatively, ARC can call:

1 void objc_destroyWeak ( id * object ) ;

Then, the object is unregistered and objc_destroyWeak calls again:

1 objc_storeWeak ( id * object , nil ) ;

This book-keeping associated with a weak reference can take 2–3 times longer over the release of a strong reference. So, a weak reference introduces an overhead for the runtime that you can avoid by simply defining outlets as strong .

I guess this decision has also something to do with the deprecated viewDidUnload method. Until iOS 5, this method was used to purge views in low-memory conditions. As explained again in the documentation:

In iOS 5 and earlier, when a low-memory condition occurred and the current view controller’s views were not needed, the system could opt to call this method (viewDidUnload) after the view controller’s view had been released. This method was your chance to perform any final cleanup. If your view controller stored separate references to the view or its subviews, you could use this method to release those references…

At that time, defining a property as weak made sense, because it avoided you having to add an additional release in the viewDidUnload . Since we are now approaching iOS 9, I believe we’ve had enough time to avoid the use of this method. So, it makes no sense to define weak to the IBOutlets.

Current Storyboard Limitations

Apple introduced storyboards in iOS 5. Before then, nib files were the only way to create a UI using Interface Builder. In iOS development, it is very common to be in the situation of handling multiple nib files in a single project. However, to understand the application flow and how view controllers are connected together, developers need to go inside each view controller class and find the bridging points to the next view controller. This is a very time consuming procedure, especially if your are not the original developer of the application.

Apple introduced Storyboards to simplify this process and help developers keep full control of the entire application flow. Indeed, storyboards allow you to keep a view controllers’ view in a single file (with extension .storyboard). In this way, you can see the entire app flow and easily understand how view controllers are connected together. On the other hand, however, storyboards also introduce some issues. Keeping all the nibs in a single file is really convenient and works perfectly, but only if you are a solo developer. As soon as your team grows and you use a version control system like git or subversion, you will start to hate storyboards. Since a storyboard contains multiple scenes, every developer of your team would need to modify this file during the development. Then, when merging the changes into a common git branch, conflicts appear, and solving these conflicts is a pain. At compile time, nibs are essentially XML files. So, to solve the merging conflicts, you need to compare 2 large XML files and try to understand what was modified by your colleague and what you modified yourself. The storyboard format is an Apple XML proprietary format that is not documented. Additionally, Apple tends to change this format quite often. So, trying to understand and reverse-engineer the storyboard format is generally a waste of time.

At iNVASIVECODE, for example, we tend to use storyboards only to prototype apps. Our designers can prototype an iOS application that can run on our client’s iOS devices in just few hours, sometimes in few minutes. This is possible using storyboards without writing a single line of code. So, storyboards are really convenient for fast prototyping, but not so much during development.

Another significant storyboard limitation is the inability to add views that do not belong to a scene hierarchy. I personally consider this a huge limitation that is more important than the previously described merging issue. Whenever I can, I use Interface Builder. I love it, because I try to avoid writing code. With storyboards, it is not possible to add extra views outside the scene hierarchy. Thus, most of the time, I am forced to use nibs, when I need extra views.

There is an additional limitation to storyboards that has to do with transitions. In iOS 7 and later in iOS 8, Apple introduced new ways to create a custom transition between two view controllers. These new methods require allocating spacial objects that cannot be used by the storyboard when you perform a segue. So, if you want to add custom transitions to your view controllers, you have to avoid storyboards.

But guess what! Xcode 7 and iOS 9 address all these issues for us.

Storyboard Reference

In Xcode 7, we have a new way to organize our scenes in multiple storyboards and keep a reference among them. Let’s see a practical example. Download this example I have prepared for you. Open it and select the Main.storyboard file. There, I already prepared for you a set of view controllers organized in a tab bar controller. Each tab contains a navigation controller. The following picture highlights the storyboard of the sample project.

As you can see, the tab bar controller embeds three navigation controllers. Each navigation controller controls different view controllers. Now, imagine working on this project with other developers. As I previously described, you will have a hard time working on the same storyboard file, because each of you will need to touch it. You can decide to split the three navigation branches into three storyboard files. However, when you try to jump from one storyboard to the next at runtime, you have to load the corresponding storyboard file. This requires adding extra code to your project.

Xcode 7 allows you to create multiple storyboards and handle them easier. Let’s see how. Select the top navigation controller and the two view controllers as shown in the following figure:

Once selected, open the menu Editor in Xcode 7 and select Refactor to Storyboard (following picture).

Assign a name to the new storyboard (see next picture). I name it First.storyboard.

Click Save. As you can see, a new storyboard has been added to your project. Let’s go back to the Main.storyboard. There, you find the following object.

This is called Storyboard Reference and it is indeed a reference to the newly created First.storyboard file and replaces the three view controllers previously selected. The cool part is that if you double click on the storyboard reference, Xcode 7 opens the referenced storyboard for you. In this way, you can easily navigate the different storyboards while also keeping full control of the application flow. At runtime, when the segue pointing to a Storyboard Reference is executed, the initial view controller of the referenced storyboard is loaded. Storyboard References can also reference the same storyboard they are in.

Alternatively, you can also create a new storyboard manually and add a Storyboard Reference to the originating storyboard. Let’s try this.

Create a new Storyboard and name it Third.storyboard. In the Main.storyboard file, add a new Storyboard Reference from the Object Library. Select that Storyboard Reference and open the corresponding Attributes Inspector. This is shown in the following figure.

In the first field, select which storyboard you want to reference (Third, in our case). If you leave this field blank, the referenced storyboard is the storyboard in which the Storyboard Reference is defined in. The Reference ID refers to a particular scene inside the destination storyboard. If you leave it empty, the initial view controller will be loaded. Finally, the Bundle field needs to be set to the name of the bundle containing the destination storyboard. If you leave it empty, the same bundle of the origin storyboard is used at runtime.

In the Third.storyboard file, you need to add a new view controller and make it the initial view controller for this storyboard. Once you have done that, you can run the app and navigate to this view controller as if it was a part of the Main storyboard.

So, now you can organize your storyboard in multiple files and keep a reference to each of them. Additionally, each storyboard can be assigned to a different developer and you don’t need to again spend time understanding how the view controllers are connected together. This is really convenient.

Scene Dock and Extra Views

This is my preferred feature. Finally, I can add to the storyboard views that are outside the scene’s view hierarchy. To show you how it works, let’s create a new project. Name it ExtraView. Open the Main storyboard. Add a new view between the First Responder and the Exit in the top bar of that view controller as shown in the following picture (this is called the Scene Dock):

Adjust the size of this view to 1500x120 pixels. Now, let’s add on top of this view another small view with size 240x112. Center this view inside the long view and add top and bottom constraints (constants = 8), the width constraint (constant = 240) and the Horizontally in Container constraint. Add also a scrollview to the view controller’s view. Center it and add the trailing and leading space to the container (constant = 0), the height constraint (constant=128), and finally add the Vertically in Container constraint. In the ViewController.swift file, add these 2 outlets:

1 2 @ IBOutlet var externalView : UIView ! @ IBOutlet var scrollView : UIScrollView !

Connect them to the scrollview and the external view. Finally, let’s add the viewDidAppear: method:

1 2 3 4 5 override func viewDidAppear ( animated : Bool ) { super . viewDidAppear ( animated ) scrollView . contentSize = externalView . frame . size scrollView . addSubview ( externalView ) }

Connect the scrollView and the externalView outlets to the scrollview and view object inside the storyboard. Run the project. As you can see, you can now add extra views (and you can add as many as you like) and simply load them at runtime. You can download the example from here.

Custom Transitions

This is an additional cool new feature of storyboards in Xcode 7. I will leave out the details for a future post, but here I just want to give you an idea on what you can do. If you select any action segue in the Multiboard project and open its Attributes Inspector, you will see that there is a new field Segue Class, as shown below:

You can now create a subclass of UIStoryboardSegue and make it conform to the UIViewControllerTransitioningDelegate protocol. Then, implement in this class the animationControllerForPresentedController: presentingController: sourceController: and animationControllerForDismissedController: . Additionally, you need to add 2 new subclasses of NSObject conforming to the UIViewControllerAnimatedTransitioning delegate. In these classes, you must implement two methods: transitionDuration: and animateTransition: .

I am leaving the details for a future post.

Conclusions

Xcode 7 added new convenient features to Storyboards. We can now create storyboard references, add views outside a scene hierarchy and use new custom view controller transitions. I also discussed why you should define outlets as a strong reference and not anymore as weak.

Geppy

Geppy Parziale (@geppyp) is cofounder of InvasiveCode (@invasivecode). He has developed iOS applications and taught iOS development since 2008. He worked at Apple as iOS and OS X Engineer in the Core Recognition team. He has developed several iOS and OS X apps and frameworks for Apple, and many of his development projects are top-grossing iOS apps that are featured in the App Store.

(Visited 536 times, 1 visits today)