Today you will learn how to perform the third storyboard operation, which is to pass data backward to a source view controller. You do this by performing an unwind segue.
Understanding The Unwind Segue Operation
First of all, an unwind segue operation involves a source view controller and a destination view controller. The source view controller is the controller from which data is being passed and the destination view controller is the controller that’s receiving the data, as shown in Figure 1 below.
Figure 1 |
Here are not to be forgotten guidelines to adhere to when performing an unwind segue and a visual of visual of them.
- Define an action method in in the destination view controller’s implementation file. This method is called before the unwind segue occur. You put code in the method to pass the source view controller’s data back to the destination view controller.
- An unwind segue can be used to navigate back through a push, modal or popover segue. Further more; you can unwind through not only one but a series of push/modal/popover segues, e.g. “go back” multiple steps in your navigation hierarchy with a single unwind action. So you should set each unwind segue’s Identity attribute. You’ll learn how to do that later on in this workshop.
- To successfully pass data back to the destination view controller, the source view controller object’s data type must match the destination view controller object’s data type. If the source view controller object’s data type doesn’t match the destination’s own, your data won’t pass back to the destination view controller. Instead an error message is displayed in the Debugger window. In some cases, the application will crash. To prevent this, you’ll have to declare a property variable (imageName) that have the same data type as the destination view controller’s object. You put your data in that property variable, then pass it to the destination view controller instead. An example of this scenario is shown in Figure 2 below. Where do you declare the imageName property variable? In the source view controller’s header file; for example, the SecondViewController.h file.
Figure 2 |
Performing an unwind segue
Now, in order to perform an unwind segue to pass data back to the destination view controller (i.e. ViewController), you’ll have to do the follow.
- Define an action method in the destination view controller (i.e. the first scene’s ViewController.m file)
- Establish the unwind segue in the storyboard by control-dragging from a UI object, such as a button control, to the scene’s Exit icon. This is shown in the image below.
Figure 3 - Select the action method you defined in the destination view controller you want to unwind to.
- Set the unwind segue’s Identity attribute in Interface Builder, so you can reference it in the unwind segue’s action method.
The key step in performing an unwind segue is, selecting the correct unwind action you defined in the destination view controller (for example ViewController).
Step 1: Add a Control on Scene 1 and Scene 2
What you need to do is pass a text string from scene 2 to scene 1 and display it in scene 1’s Label control. To do that, you’ll have to add a Label control on Scene 1, as shown in Figure 1-1 below. Set the Label control’s Alignment attribute to center its text. Set the Label control’s text color to Teal, and enter A message will appear here in the Text box.
Figure 1-1: Add a Label control on scene 1 |
Step 2: Use The Assistant Editor to Create and Connect an IBOutlet Property
To be able to set the Label control’s Text attribute in code, you need to create an IBOutlet property and connect it to the Label control. Start by opening the Assistant editor (its icon looks like a butler with a bow tie) and make sure it has correlated the ViewController.h file onto the right-hand pane of the Split View. If not, then select the file from the right-hand pane’s jump bar. The jump is located above the code editor. Now, control-drag from the Label control to the ViewController.h file, dropping it directly under the @interface ViewController line as shown in Figure 2-1.
Figure 2-1 |
After you drop the connector into the ViewController.h file, a connection dialog box appears. Keep this connection type as an Outlet and enter messageLabel in the Name field then click the Connect button. (The Label suffix reminds you that a label is connected to this outlet.) This dialog is illustrated in Figure 2-2 below.
Figure 2-2 |
As you can see in the right-hand pane of the Assistant editor, Xcode created the IBOutlet property and connected it to the Label control for you. This is illustrated in Figure 2-3 below.
Figure 2-3: Connection made for the Label control |
Next, add a textField control on scene 2, below the Button control. Figure 3-1 below shows what it should look like in Interface Builder. Use the Assistant editor to create and connect this property for it.
@property (strong, nonatomic) IBOutlet UITextField *textFieldMessage;
Now, add this statement in the SecondViewController.m file’s viewDidLoad method, which sets the Text Field control’s Text attribute.
self.textFieldMessage.text = @"Storyboarding is cool!";
Step 3: Pass Your Data Back to Scene 1
What we want to do is pass scene 2’s Text Field value back to scene 1. This mean you’ll have to define an action method in the destination view controller (ViewController), then wire it to the source view controller’s (SecondViewController) Exit object.
Start by adding this code at the top of the ViewController.m file, which import the SecondViewController header file.
#import "SecondViewController.h"
Next, define this action method in the ViewController.m file. As you already know, it is fired prior to an unwind segue. So it is the perfect place to pass scene 2’s Text Field value to scene 1’s Label control.
- (IBAction)returnedFromScene2:(UIStoryboardSegue *)segue { if([segue.identifier isEqualToString:@"showScene1"]) { // Put the destination view controller and source view controller in separate variables ViewController *destination = [segue destinationViewController]; SecondViewController *source = [segue sourceViewController]; // Pass scene 2's Text Field value to scene 1's Label control destination.messageLabel.text = source.textFieldMessage.text; } }
As you can see, I have documented above method’s code; so you should have no problem understanding it. However; there are two things I want to point out about the unwind segue.
The unwind segue’s action method has a single parameter, segue and it contain these three objects.
- identifier – This is a unique name you give a segue so you can reference it in code. For example, above if statement shows exactly how you reference the segue’s identifier created for the first scene’s Goto Scene 2 button control. You’ll set the segue’s identifier in step 4 below, via Interface Builder’s Attribute Inspector pane.
- sourceViewController – This is a pointer to the second scene’s view controller, which is called SecondViewController. As you saw in code line 06 above we assigned this pointer object in a variable called source.
- destinationViewController – This is a pointer to the first scene’s view controller, which is called ViewController. As you saw in code line 05 above we assigned this pointer object in a variable called destination.
You can view the objects stored in the segue parameter by using the NSLog() function in the prepareForeSegue: method like this:
Source Code |
NSLog(@"Source Controller: %@",segue.sourceViewController); NSLog(@"Destination Controller: %@",segue.destinationViewController); NSLog(@"Segue Name: %@",segue.identifier); |
Output |
Source Controller: <ViewController: 0x8dcdfc0> Destination Controller: <SecondViewController: 0x8d84e20> Segue Name: showScene2 |
The unwind segue view controllers objects’ data types must match. Remember what I said earlier on about the unwind segue view controller object’s data type:
To successfully pass data back to the destination view controller, the source view controller object’s data type must match the destination view controller object’s data type. If the source view controller object’s data type doesn’t match the destination’s own, your data won’t pass back to the destination view controller.
Well, this statement will execute successfully because both controllers objects’ data type match. They are of type NSString.
destination.messageLabel.text = source.textFieldMessage.text;
Step 4: Create The Unwind Segue
What you need to do now is establish the unwind segue. To do that, click the Main.storyboard file and locate scene 2. Control-click and drag from the button control to the Exit object, as shown in the Figure 3-1. Release the mouse button and select the returnedFromScene2: method from the resulting menu.
Figure 3-1: Establish the unwind segue |
Step 5: Set The Identity Attribute for The Unwind Segue
The last thing you need to do is set the unwind segue’s Identity attribute in Interface Builder. Why? So you can quickly identify it from other segues in the Outline Document pane and reference it in code. Click the Main.storyboard file, click the Document Outline toggle to show it, click the Unwind segue item. Click the Attribute Inspector to show it in the Utilities pane. Now, enter showScene1 in the Identity box. When you’re done, your Xcode workspace should look like this:
Figure 5: Set the unwind segue’s Identity attribute |
Run the application and note that the button on scene 2 now returns to scene 1 and, in the process, calls the returnedToScene1: method resulting in a text string appearing in scene 1’s Label control.
That’s it. Now you know how to pass data backward to a source view controller by performing an unwind segue. Next week, you will implement the final storyboard operation, which is to, pass data forward to a destination view controller. Until then, happy coding! 🙂