Handle data and events from your modal view controller with a formal protocol

Apple recommends that “When it comes time to dismiss a modal view controller, the preferred approach is to let the parent view controller do the dismissing”. In this document, you learn how to implement this approach.

This document was most recently updated in September 2011.

.

Apple recommends…

Recently, you learned how to work with a modal view controller.

One of the issues is the handling of data that the modal view controller generates. Another issue is the dismissal of the modal view controller.

As suggested by the pattern you saw with the alerts and action sheets topic, Apple recommends, in the View Controller Programming Guide for iOS:

When it comes time to dismiss a modal view controller, the preferred approach is to let the parent view controller do the dismissing.

Although there are several techniques for notifying a parent view controller that it should dismiss its modally presented child, the preferred technique is delegation.

In a delegate-based model, the view controller being presented modally must define a protocol for its delegate to implement. The protocol defines methods that are called by the modal view controller in response to specific actions, such as taps in a Done button.

The delegate is then responsible for implementing these methods and providing an appropriate response. In the case of a parent view controller acting as a delegate for its modal child, the response would include dismissing the child view controller when appropriate.

.

The sections that follow guide you through the implementation of this approach:

  1. Defining a formal protocol
  2. Calling a protocol’s method
  3. Implementing a protocol’s method

.

Code example – To Do Add

The To Do Add code example shows how this is done. Download it, open it in Xcode, and we’ll work through it in the sections below.

.

Defining a Formal Protocol

In the code example, there is a view controller named AddNewItem. We will define the formal protocol in the interface source code file, AddNewItem.h.

First, before the @interface… declaration, add the following:

@protocol AddNewItemDelegate;

.

This is a “forward declaration”. (You’ve seen that before with the @class… statement.) It is simply a declaration to the compiler that the protocol is declared elsewhere. We do this to prevent compilation errors.

Next, we define a “delegate” property for this AddNewItem class. When an instance of this class is created, the delegate property can be assigned. Here’s the property declaration:


@property (nonatomic, assign) id <AddNewItem> delegate;

.

The property declaration requires some explanation. First, note the “assign” memory management. Next, the property’s type is id. As you’ve learned, “id is a pointer to an object of any type”. What this means is that any object can become a delegate to the AddNewItem class.

Next, you see the <AddNewItemDelegate> syntax. This simply means that the delegate object will conform to the AddNewItemDelegate protocol. Then, the “delegate” property name is declared, which is the standard name.

Now, switch to the AddNewItem.m implementation source code. Synthesize the “delegate” property, and do the memory management task ([delegate release];). Switch back to the AddNewItem.h interface source code.

Finally, below the @end declaration, we add our formal protocol declaration:

@protocol AddNewItemDelegate

// By default, methods are "required"; you can change this by prefacing methods with "@optional"
- (void) addNewItemController:(AddNewItem *)addNewItemController didAddNewItem:(NSString *)newItem;

@end

.

As you can see, we have decided that one required method needs to be implemented by adopters of this formal protocol. The method will enable the adopter to pass back data (an NSString), so that we can do something with it. As you have learned (from using other protocols), you will implement the method in the delegate object.

More information about declaring a formal protocol is found in the Objective-C Programming Language documentation from Apple.

.

Calling a protocol’s method

In the AddNewItem class, methods were defined that will handle the “save” and “cancel” events from the user interface. In those methods, you will write code that calls a method that was defined in the protocol.

Switch to the AddNewItem.m implementation source code file.

In the “save” method block, prepare the data that you want to send to the delegate (in this situation, it will come from the UITextView’s “text” property), and then call the protocol’s method that you defined earlier:

	[self.delegate addNewItemController:self didAddNewItem:self.tfNewItem.text];

.

In the “cancel” method block, call the protocol’s method, but this time, send “nil” as the data:

	[self.delegate addNewItemController:self didAddNewItem:nil];

.

Implementing a protocol’s method

You have learned about the delegation pattern in the past couple of weeks. You know the following:

  • Often in a controller class, you adopt (conform to) a protocol, by adding <syntax> to the class’ interface
  • Then, you implement the protocol’s required and one or more of its optional methods in the class’ implementation

.

In today’s coverage of alerts, action sheets, and system-provided modal view controllers, you learned one more thing:

  • When declaring and implementing a new view controller in code, you often need to configure a delegate for that new view controller

.

Therefore, in today’s To Do Add code example, you will do these three tasks, in the To_Do_AddViewController module.

.

Declaration in the interface

Add another “import” statement to the .h interface (located just below the template-provided #import <UIKit/UIKit.h> statement):

#import "AddNewItem.h"

.

Next, make the interface adopt (conform to) the AddNewItemDelegate protocol:


@interface To_Do_AddViewController : UIViewController <AddNewItemDelegate> {

.

In the code block that creates the modal view controller, make sure that you set its delegate property. This To_Do_AddViewController will be the delegate of the AddNewItem view controller:

	// Create the second view controller
	AddNewItem *addVC = [[AddNewItem alloc] initWithNibName:@"AddNewItem" bundle:nil];

	// Configure it (assign/set the delegate)
	addVC.delegate = self;

	// Present it
	[self presentModalViewController:addVC animated:YES];

.

Finally, implement the delegate method. The AddNewItem view controller instance will call this delegate method. It will pass on a reference to itself (because we designed it to do that), and the data that was generated during the lifetime of the AddNewItem view controller.

Notice the pattern that tests whether the passed-on data is nil. This enables you to determine whether to attempt to process incoming data.

After the data gets processed, this “parent” view controller dismisses the modal view controller:

// DELEGATE METHOD - handle the message from the AddNewItem view controller
- (void) addNewItemController:(AddNewItem *)addNewItemController didAddNewItem:(NSString *)newItem {

	// Handle the incoming data/object
	if (newItem) {
		self.toDoList = newItem;
	}

	// Dismiss the modal view controller
	[addNewItemController dismissModalViewControllerAnimated:YES];
}

.

Summary

This document showed you how to declare and implement a formal protocol. It built upon your past experience with pre-defined protocols, and the delegation pattern.

The new concepts included the following:

  1. How to declare a formal protocol – concepts and syntax
  2. In the “agent” (i.e. the caller), how to call a protocol’s method
  3. Setting the delegate property of a view controller
  4. Implementing a delegate method

.

Happy coding!

.


.

.

.

Advertisements
  1. Philip Ryan
    September 10, 2012 at 2:43 am

    Thanks for this! Delegation properly explained and demonstrated.

    The terminology of who and what is doing the delegation isn’t entirely consistent, or maybe it just isn’t well explained anywhere. To my mind, the delegator is the class doing the delegating, the delegate is the class being delegated to do the work… but the problem is that in most actual uses, the “important” class is the delegate class.

    Anyway, now delegation is allowing me to run custom view controllers and just ‘return’ the information from one VC to another. Thanks!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: