Protocols are a great way to delegate responsibility from one class to another.
Consider a view controller that brings up another view controller via a modal segue. Let’s call them ViewController and DetailViewController. When it comes to dismissing that DetailViewController, he could do it himself via
[self dismissViewControllerAnimated:YES completion:nil];
However, the first ViewController wouldn’t be in charge of that process. If we wanted to make that happen, we can define a protocol on DetailViewController, then have ViewController conform to it and hence be in charge of the dismissal.
Let’s make it happen!
Defining the Protocol
Most of the work happens in the header file of DetailViewController:
#import <UIKit/UIKit.h> @protocol DetailViewDelegate; @interface DetailViewController : UIViewController @property (nonatomic, weak) id <DetailViewDelegate> delegate; - (IBAction)dismiss:(id)sender; @end @protocol DetailViewDelegate - (void)detailViewDismiss; @end
Right after the import statement, we say “we’ll define a protocol in here”. Next we setup a weak property called delegate so that we can declare a delegate elsewhere (other than self).
After the first @end statement we define one method that the delegate must confirm to. By default, all methods we define are “required” by the delegate – if we don’t implement them all, then we’ll get a yellow warning mark in Xcode.
We don’t have to define these methods in the implementation file. Instead, we would define where we would like our delegate to execute them. I have one method which will get called when a button on DetailViewController is pressed:
- (IBAction)dismiss:(id)sender { [self.delegate detailViewDismiss]; }
All we do here is say “yo delegate, call my dismiss method and do in it whatever you like”.
Confirming to the protocol
We’ve done this countless times with built-in classes, and the process is exactly the same for our own protocols:
– add the delegate protocol in
– implement the methods in the implementation file
Here’s the very simple ViewController.h header file (ie “the guy who’s in charge”):
#import <UIKit/UIKit.h> #import "DetailViewController.h" @interface ViewController : UIViewController <DetailViewDelegate> @end
And in the implementation file we’d define our only delegate method:
- (void)detailViewDismiss { [self dismissViewControllerAnimated:YES completion:nil]; }
The only remaining thing is to tell DetailViewController who the delegate is. In case of a modal segue like ours this can be done in the prepareForSegue:sender method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { DetailViewController *detailView = (DetailViewController *)[segue destinationViewController]; detailView.delegate = self; }