Design Patterns: Delegation - Notes

From:Design Patterns: Delegation by Bart Jacobs

1. What Is Delegation?

The definition of the delegation pattern is short and simple. This is how Apple defines the pattern.

A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program.

2. Example

The UITableViewDelegate protocol

An important difference between Swift and Objective-C is the possibility to mark protocol methods as optional. In Objective-C, the methods of a protocol are required by default. The methods of the UITableViewDelegate protocol, however, are optional. In other words, it is possible for a class to conform to the UITableViewDelegate protocol without implementing any of the protocol’s methods.

In Swift, however, a class conforming to a particular protocol is required to implement every method defined by the protocol. This is much safer since the delegating object doesn’t need to verify whether the delegate implements a protocol method. This subtle, but important, difference is illustrated later in this tutorial when we implement the delegation pattern.

Data Source

The data source pattern fits nicely in the Model-View-Controller or MVC pattern. Why is that? A table view, for example, is part of the view layer. It doesn’t and shouldn’t know about the model layer and isn’t in charge of handling the data that is coming from the model layer. This implies that the data source of a table view, or any other view component that implements the data source pattern, is often a controller of some sort. On iOS, it’s usually a UIViewController subclass.

3. Implementation

Objective-C

Project on GitHub

recipient:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// AddItemViewController.h

#import <UIKit/UIKit.h>

@protocol AddItemViewControllerDelegate;

@interface AddItemViewController : UIViewController

@property (weak, nonatomic) id<AddItemViewControllerDelegate> delegate;

@end

@protocol AddItemViewControllerDelegate <NSObject>
- (void)viewControllerDidCancel:(AddItemViewController *)viewController;
- (void)viewController:(AddItemViewController *)viewController didAddItem:(NSString *)item;

@optional
- (BOOL)viewController:(AddItemViewController *)viewController validateItem:(NSString *)item;
@end

We declare a class, AddItemViewController, which extends UIViewController. The class declares a property, delegate, of type id. Note that the property is marked as weak, which means that an AddItemViewController instance keeps a weak reference to its delegate.

1
2
3
4
5
6
7
// AddItemViewController.m

- (IBAction)cancel:(id)sender {
if (self.delegate && [self.delegate respondsToSelector:@selector(viewControllerDidCancel:)]) {
[self.delegate viewControllerDidCancel:self];
}
}

Sender:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// ViewController.m

#import "ViewController.h"
#import "AddItemViewController.h"

@interface ViewController () <AddItemViewControllerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (IBAction)addItem:(id)sender {
// Initialize View Controller
AddItemViewController *viewController = [[AddItemViewController alloc] init];

// Configure View Controller
[viewController setDelegate:self];

// Present View Controller
[self presentViewController:viewController animated:YES completion:nil];
}

- (void)viewControllerDidCancel:(AddItemViewController *)viewController {
// Dismiss Add Item View Controller

}

@end

Swift

Project on GitHub

In Swift, the delegation pattern is just as easy to implement and you’ll find that Swift makes delegation slightly more elegant. Let’s implement the above example in Swift. This is what the AddItemViewController class looks like in Swift.

recipient:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// AddItemViewController.swift
import UIKit

protocol AddItemViewControllerDelegate: NSObjectProtocol {
func viewControllerDidCancel(viewController: AddItemViewController)
func viewController(viewController: AddItemViewController, didAddItem: String)
func viewController(viewController: AddItemViewController, validateItem: String) -> Bool
}

class AddItemViewController: UIViewController {
var delegate: AddItemViewControllerDelegate?

func cancel(sender: AnyObject) {
delegate?.viewControllerDidCancel(self)
}
}

The protocol declaration looks a bit different in Swift. Note that the AddItemViewControllerDelegate protocol extends the NSObjectProtocol instead of the NSObject protocol. In Swift, classes and protocols cannot have the same name, which is why the NSObject protocol is named differently in Swift.


Let’s now look at the ViewController class, which implements the AddItemViewControllerDelegate protocol. The interface shows us that the ViewController class extends the UIViewController class and adopts the AddItemViewControllerDelegate protocol.

Sender:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// ViewController.swift

import UIKit

class ViewController: UIViewController, AddItemViewControllerDelegate {
func addItem(send: AnyObject) {
// Initialize View Controller
let viewController = AddItemViewController()

// Configure View Controller
viewController.delegate = self

// Present View Controller
presentViewController(viewController, animated: true, completion: nil)
}

func viewControllerDidCancel(viewController: AddItemViewController) {
// Dismiss Add Item View Controller
...
}

func viewController(viewController: AddItemViewController, didAddItem: String) {

}

func viewController(viewController: AddItemViewController, validateItem: String) -> Bool {

}
}

4. Conclusion

Delegation is a pattern you’ll come across frequently when developing iOS and OS X applications. Cocoa relies heavily on this design pattern so it’s important to become familiar with it.

Since the introduction of blocks, a few years ago, Apple has slowly offered an alternative blocks-based API to some delegation implementations. Some developers have followed Apple’s lead by offering their own blocks-based alternatives. The popular AFNetworking library, for example, relies heavily on blocks instead of delegation, resulting in an elegant, intuitive API.