Passing Data Between View Controllers

iOS View Controller Transitions served as an introduction to an efficient and extensible solution for transitioning between view controllers. In this article, we will use the same Mediator Pattern structure as a base for tackling the issue of injecting and passing data between view controllers.1

We will be using the same three view controller hierarchy: ViewControllerA, ViewControllerB and ViewControllerC, all embedded in a navigation controller.

Passing Data Between View Controllers

In this example, each view controller has a button for transitioning to the next view controller and an object that needs to be passed from one controller to the next. What most people do when the time for a segue comes, looks something like this:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"SEGUE_NAME_AS_IN_STORYBOARD"])
    {
        // Get reference to the destination view controller
        ViewControllerB *vc = [segue destinationViewController];

        // Pass any objects to the view controller here
        vc.myObject = self.myObject;
    }
}

 

The Problem

ViewControllerC needs a property of ViewControllerA but they are not directly “connected”.

This has the potential to lead to some really ugly situations. What usually happens is that the property in question gets passed to ViewControllerC indirectly through ViewControllerB. This means that ViewControllerB holds a property that it does not need. All it needs it for, is to pass it along to ViewControllerC; if and when the time comes. This is wrong on many levels.

First, it violates the Single Responsibility Principle. View controllers (and “controller” classes in any MVC structure in general) are code-wise heavy by nature. Enforcing an extra responsibility burdens the controller with further knowledge of its surroundings.

Also, every time someone needs to work with ViewControllerB they will assume/expect (when looking at the header file) that the property in question is useful in some way for the core functionality of this class. This is going to lead to confusion. What if ViewControllerB has to be removed or replaced? This dependency is an extra relationship that needs to be maintained and its intent (reason of existence) is not clear.

“It’s ok, you can use comments for that!”

I was refactoring a Flash/PHP hybrid CRM application many years ago when I first met the dreaded comment, the one that goes something like “Please ignore this variable, it’s only used for this or that”. Worst, it was probably written by me.

This is a risk bearing and irresponsible 2 way of handling the issue of injecting dependencies and asks for safer options that handle requirement changes gracefully.

The Solution

Again, the problem can be solved by “outsourcing” communications’ management to an intermediate  class using the Mediator Design Pattern.

Passing Data Between View Controllers

In the “before” diagram above, if ViewControllerA wants to pass myObjectB to ViewControllerC or ViewControllerD, it has to do so by first passing it to ViewControllerB which will later pass it on to ViewControllerC etc. This architecture is prone to producing errors and is a maintenance nightmare.

By introducing a Mediator to handle the injections, our problem is solved because the mediator handles the passing of data between any two view controllers now. View controllers C and D no longer depend on ViewControllerB to gain access to a property/object of ViewControllerA. If ViewControllerB has to be replaced, view controllers C and D won’t “break” (unlike before).

To unburden the Mediator (in the case of apps with lots of transitions, segues and scenes), the State Design Pattern can be thrown into the mix.

Further Reading

Books:

Design Patterns: Elements of Reusable Object-Oriented Software (The Gang Of Four Book)

Head First Design Patterns (In my experience, the best introductory book on Design Patterns)

Pro Objective-C Design Patterns for iOS

Agile Principles, Patterns, and Practices in C# (Uncle Bob’s seminal book, a must read)

Articles:

Lighter View Controllers (Give your view controllers some space to breathe)

Single Responsibility Principle (The principle defined by the godfather of the term)


  1. Again, this problem is not unique to iOS. Feel free to apply the concepts described here in any situation you see fit.

  2. There is a reason why I am using strong language here. These things really matter.