How to Add a Modal View in Your iOS App
Most of the time, the user can control what is happening in iOS apps. You provide the buttons and other interface elements, but the user chooses what to do and what interface elements to tap. Modal views interrupt that user control. They are presented on the screen and, although the user can tap within them, they remain front and center until the user dismisses them.
They are used when you want the user to do something or resolve an issue before continuing to use the rest of the app. The device is not locked up because the user can use the Home button to move to another app, but as far as your app is concerned, it’s frozen until the modal view is dismissed.
The most common way to manage Modal views is by creating an Objective-C protocol that’s adopted by the controller presenting the Modal view. The Modal view, when the user has selected an action or Cancel, sends a message to the presenting controller’s delegate method. The requesting controller then dismisses the Modal controller.
Using this approach means that, before it dismisses the Modal controller, the presenting controller can get any data it needs from it. That is the pattern that you will implement here.
You start implementing the Modal view by declaring the protocol and a few other properties you’ll need, as well as the protocols the DestinationController needs to adopt.
To get things started, add the bolded code in Listing 20-1 to DestinationController.h.
#import <UIKit/UIKit.h> @protocol DestinationControllerDelegate; @interface DestinationController : UIViewController <UITableViewDelegate, UITableViewDataSource> @property (weak, nonatomic) IBOutlet UITableView *destinationTableView; @property (strong, nonatomic) id <DestinationControllerDelegate> delegate; @property (nonatomic, readonly) NSUInteger selectedDestination; - (IBAction)cancel:(id)sender; –d @protocol DestinationControllerDelegate @required - (void)destinationController: (DestinationController *)controller didFinishWithSave:(BOOL)save; –d
The Objective-C language provides a way to formally declare a list of methods(including declared properties) as a protocol. You’ve used framework-supplied protocols extensively in this book, and now you’re defining your own protocol.
You declare formal protocols with the @protocol directive. You declared a DestinationControllerDelegate protocol with one method, destinationController:didFinishWithSave:, which is required. Required is the default; if you wanted to declare optional methods, you would use the keyword @optional, and all methods following that keyword would be optional. For example, consider this:
@protocol SimpleDelegate @optional - (void)doNothing; –d
You can have both @required and @optional methods in a protocol. It is common to group them together, but you can intersperse them if you want.
If neither @required or @optional is specified, @required is assumed. However, it is better to be specific about what is required and what is optional. The @protocol DestinationControllerDelegate: statement (at the top) tells the compiler that a protocol is on the way. Like the @class statement, it says, “Trust me, you’ll find the protocol.” You need this here only because you added this:
@property (strong, nonatomic) id <DestinationControllerDelegate> delegate;
This statement tells the compiler to type check whatever it is you assign to delegate to make sure that it implements the DestinationControllerDelegate protocol.
You also added the selectedDestination property, which you’ll use in the ViewController to determine which destination the user selected. Notice that you have made it read-only because there is no reason for any other object to be able to set it.
You also adopted two protocols from the Cocoa Touch framework, UITableViewDelegate and UITableViewDataSource, which you’ll use to manage the Table view.
Next, you’re going to need to update the DestinationController implementation with the bolded code for some header files you’ll need to use later.
#import "DestinationController.h" #import "DetailViewController.h" #import "AppDelegate.h" @interface DestinationController () –d @implementation DestinationController
Now that you have the plumbing in, you can look at what will go on in the DestinationController.