Using Storyboards

We generally do not use Storyboards in our projects where I work. That’s mainly because, at least as of iOS 6, they cannot be merged. This means that only a single developer can make changes to a storyboard at any given time. However, it appears that Apple is working on correcting this situation. So I’ve been taking another look at Storyboards, and investigating how these can be integrated into our best practices (TDD, clean code and architecture).

The first question that I had was “how to unit testing view controllers loaded from a storyboard?”. This appears to be fairly easy, and I found the answer on Rafael Adson’s blog. Simply load the view controller from the storyboard in the test setUp method:

- (void)setUp
{
    [super setUp];
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    self.vc = [storyboard instantiateViewControllerWithIdentifier:@"main"];
    [self.vc performSelectorOnMainThread:@selector(loadView) withObject:nil waitUntilDone:YES];
}

You’ll need to set the identifier for the view controller in the storyboard, and then modify the code above to match the name of your storyboard and the id you chose for the view controller.

The second question is how to integrate storyboards into the VIPER architecture. First off, it seems that the storyboard should replace the wireframe component. But there’s a problem. Normally the wireframe would be responsible for creating the view controller, interactor, and presenter. But the storyboard only creates a view controller.

Now, we can easily have the view controller’s viewDidLoad method create the interactor and presenter, but that results in making the view controller aware of those components. From a clean architecture perspective, we’d prefer that these components remain as detached from each other as possible.

That said, I don’t know how the storyboard can be used to create all three components, so I guess we’re stuck with the viewDidLoad hack at this point. I’m continuing to investigate, and I’d love to hear your suggestions.

5 thoughts on “Using Storyboards

  1. When a ViewController be init by Storyboard, there are two ViewController method have been called:

    – (id)initWithCoder:(NSCoder *)aDecoder;

    – (void)viewDidLoad;

    Is this a way to detach Interactor and Presenter?

    1. Using viewDidLoad is a convenient way to create the Interactor and Presenter, but it creates an undesirable dependency. The ViewController must then know about those other components. It would be better if just the wireframe component (storyboard in this case) had to know about, and create the ViewController, Interactor, and Presenter.
      For more info on this, refer to Uncle Bob’s CleanCode book or his videos on CleanCoders.com.

  2. How about dragging and dropping NSObjects into the storyboard view controller scene and using their awakeFromNib methods. This will create no dependency in code. However, the objects will be instantiated only when the view controller is unarchived, so there still will exist an indirect dependency. A little better than doing it in viewDidLoad I guess but doesn’t totally solve the problem.

  3. How do you handle universal app’s storyboards? Imagine that the iPad version doesn’t have any additional controls, how would you ensure both storyboards wire up their view controller’s components right?

Leave a Reply