Delegate in Swift

·

4 min read

When you develop apps with Swift, you would often see delegates such as UITableViewDelegate, AppDelegate, and handling APIs. Today, I will explain about the delegate in Swift.

TL;DR

In Swift, the delegate is a design pattern that allows an object to delegate tasks to another object, without the need for the delegating object to have detailed implementation of tasks.

Literal meaning of "delegate"

According to a dictionary, "delegate" means:

  • (noun) a person designated to act for or represent another or others.

  • (verb) to commit (powers, functions, etc.) to another as agent or deputy.

As its literal meaning, the "delegate" assigns the implementation of specific process to other objects in Swift programming.

It's just a design pattern

The delegate is just a design pattern; you can develop apps without using the delegate pattern.

In OOP languages like Swift, applications are made up of many kinds of objects and work through interactions of these objects. Once you define an object using a class or a struct, you ca reuse it many times in your application. This reusability of objects is a main feature in OOP languages.

The delegate is a functionality of Swift for making your application more reusable and readable. In this sense, the delegate is just a design pattern rather than a basic functionality in Swift. Therefore, you can develop your applications without the delegate pattern, but the delegate will help you in some ways (which I will explain later).

Three key components of the delegate

When you use a delegate pattern in your apps, you have to implement three kinds of component: the delegate protocol, the delegating object, and the delegate object. Let's explore each components with example codes.

Delegate protocol

It is a protocol that defines a set of methods that the delegate object should implement. The delegate protocol serves as a contract between the delegate object and the delegating object, specifying the methods that the delegate should provide. The methods in the delegate protocol commonly represents events, callbacks, or data-related queries that the delegating object can invoke on the delegate object.

protocol ButtonDelegate {
    func audio()
    func background()
}

As the example codes, the delegate protocol just declare methods without providing any detailed implementation. The detailed implementation of delegate methods are typically done in the delegate objects.

Note

  • With the AnyObject protocol, the protocol will only be used with only classes not a struct or enum.

Delegate object

This is the object that conforms to the delegate protocol and implements the required methods.

class Button1: ButtonDelegate {
    func audio() {
        print("Sound 1")
        // perform audio-related tasks
    }
    func Background() {
        print("Backgroun 1")
        // perform background-related tasks
    }
}

The delegate object is responsible for responding to the events, callbacks, and queries invoked by the delegating object.

Delegating objects

It is the object that has a reference to the delegate object and defines a delegate property to hold a reference to the delegate object.

class Button {
    var delegate: ButtonDelegate? = nil
    func click() {
        print("button clicked")
        if let dg = self.delegate {
            dg.audio() // delegate method
            dg.background() // delegate method
        } else {
            print("Do nothing")
        }
    }
}

The delegating object communicates with the delegate object by invoking methods defined in the delegate protocol.

Thanks to the delegate protocol, delegate object, and delegating object, you can use the delegate pattern like this:

let button = Button()

let button1 = Button1()
button.delegate = button1
button.click()
// OUTPUT
// button clicked
// Sound 1
// Backgroun 1

How the delegate benefits you

When you define an object with delegate pattern, you do not need to worry about what class performs a specific process and what kind of process should be implemented, which the delegate object will do. In the example above, when you want to invoke some different event from "Button1", all you have to do is define a new delegate object not re-define "Button1" class.

class Button2: ButtonDelegate {
    func audio() {
        print("Sound 2")
        // perform audio-related tasks
    }
    func Background() {
        print("Backgroun 2")
        // perform background-related tasks
    }
}

let button = Button()

let button2 = Button2()
button.delegate = button2
button.click()
// OUTPUT
// button clicked
// Sound 2
// Backgroun 2

In this way, the delegate make your apps more reusable, flexible, and extensible.