Swift Language Delegate pattern

Download Swift Language for free

Example

A delegate is a common design pattern used in Cocoa and CocoaTouch frameworks, where one class delegates responsibility for implementing some functionality to another. This follows a principle of separation of concerns, where the framework class implements generic functionality while a separate delegate instance implements the specific use case.

Another way to look into delegate pattern is in terms of object communication. Objects often needs to talks to each other and to do so an object need conform to a protocol in order to become a delegate of another Object. Once this setup has been done, the other object talks back to its delegates when interesting things happens.

For example, A view in userinterface to display a list of data should be responsible only for the logic of how data is displayed, not for deciding what data should be displayed.

Let's dive into a more concrete example. if you have two classes, a parent and a child:

class Parent { }
class Child { }

And you want to notify the parent of a change from the child.

In Swift, delegates are implemented using a protocol declaration and so we will declare a protocol which the delegate will implement. Here delegate is the parent object.

protocol ChildDelegate: class {
    func childDidSomething()
}

The child needs to declare a property to store the reference to the delegate:

class Child {
    weak var delegate: ChildDelegate?
}

Notice the variable delegate is an optional and the protocol ChildDelegate is marked to be only implemented by class type (without this the delegate variable can't be declared as a weak reference avoiding any retain cycle. This means that if the delegate variable is no longer referenced anywhere else, it will be released). This is so the parent class only registers the delegate when it is needed and available.

Also in order to mark our delegate as weak we must constrain our ChildDelegate protocol to reference types by adding class keyword in protocol declaration.

In this example, when the child does something and needs to notify its parent, the child will call:

delegate?.childDidSomething()

If the delegate has been defined, the delegate will be notified that the child has done something.

The parent class will need to extend the ChildDelegate protocol to be able to respond to its actions. This can be done directly on the parent class:

class Parent: ChildDelegate {
    ...

    func childDidSomething() {
        print("Yay!")
    }
}

Or using an extension:

extension Parent: ChildDelegate {
    func childDidSomething() {
        print("Yay!")
    }
}

The parent also needs to tell the child that it is the child's delegate:

// In the parent
let child = Child()
child.delegate = self

By default a Swift protocol does not allow an optional function be implemented. These can only be specified if your protocol is marked with the @objc attribute and the optional modifier.

For example UITableView implements the generic behavior of a table view in iOS, but the user must implement two delegate classes called UITableViewDelegate and UITableViewDataSource that implement how the specific cells look like and behave.

@objc public protocol UITableViewDelegate : NSObjectProtocol, UIScrollViewDelegate {
        
        // Display customization
        optional public func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
        optional public func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
        optional public func tableView(tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int)
        optional public func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
        ...
}

You can implement this protocol by changing your class definition, for example:

class MyViewController : UIViewController, UITableViewDelegate

Any methods not marked optional in the protocol definition (UITableViewDelegate in this case) must be implemented.

Implementing Hashable protocol