The Holy Grail of UIKit: Delegate Pattern
Tags: ios, swift, architecture
Published: 2021-10-20 19:15:04

---
title: The Holy Grail of UIKit: Delegate Pattern
published: true
date: 2021-10-20 19:15:00 UTC
tags: ["ios", "swift", "architecture"]
canonical_url: https://tarikdahic.com/posts/the-holy-grail-of-uikit-delegate-pattern/
---

When I started learning to develop apps for iOS I stumbled upon the delegate pattern for the first time. Adopting _UITableViewDataSource_ and _UITableViewDelegate_ protocols felt very strange and confusing.

> Why am I doing this? Is this really how to do these things? I asked myself.

After a couple of weeks of learning and reading materials, I clicked and really started to enjoy using this pattern.

## What is it?

According to Apple:

> Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases, it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.

This is a very good definition. But let’s take it step by step by following the illustration below.

![](https://tarikdahic.com/images/delegate-illustration.png)

1. Someone creates a **Worker**. A Worker is someone who does the work and then notifies us when the work is _completed_ or when something is _needed_ to continue the work.
2. We tell the worker: “_This is your delegate. Ask it for something or notify it when you are done._”. That depends on the language that is known between the worker and its delegate. This is always known upfront.
3. The Worker starts to work.
4. While the Worker is working it needs some data to continue its work. The worker asks its delegate “_How should I do this or that?_” and the delegate knowing what the worker needs provides it. When the Worker finishes the work it can tell its delegate “_I finished the work and here are the results!_”.

This is how the delegate pattern works. The communication flow is always 1-to-1 between the delegate and the worker.

The worker is always doing the same job, but by providing different data and reacting differently on work completions we can reuse the worker in a lot of places where we need to handle the different cases.

Delegation works great when there is a clear relationship between the owner and the “_Worker_”. For other cases, you will want to resort to other patterns.

I would also like to repeat that the worker knows what to send or request from the delegate.

## Translating this into code

After we’ve covered the basics with the theory we will try to translate this into code. I will be using Swift to implement this pattern.

### Define the protocol

We should always start with the delegate protocol, the interface or the language that will the delegate adopt and that the worker will know in advance.

```swift
protocol WorkerDelegate: AnyObject {
    func didFinishWork()
}
```

I declared _WorkerDelegate_ protocol that has one method for this example and that is _didFinishWork()_. When the worker completes the work it will use the delegate that has conformance to _WorkerDelegate_ protocol and will call the _didFinishWork()_ method on it.

#### AnyObject

You can notice that the _WorkerDelegate_ protocol conforms to another one and that is **AnyObject**. We use AnyObject to limit that only class types can inherit our delegate protocol. Only class objects can be weak because they are passed by reference and we want weak delegates so that we don’t create **retain cycles** while using delegates.

### Define the worker

```swift
class Worker {
    weak var delegate: WorkerDelegate?

    func startWork() {
        // Start some work..
        //
        //
        // .. and when it is completed, notify the delegate:
        delegate?.didFinishWork()
    }
}
```

The Worker class has a property **delegate** that is of type _WorkerDelegate_. It has a weak reference to something that will be stored in this variable and that is, as I mentioned above to avoid creating potential retain cycles. The delegate is also optional so by default it is **nil**. This is useful in some cases where setting the delegate is not mandatory.

The Worker has a _startWork()_ method that will start some work and when the work is completed it will notify its delegate by invoking the _didFinishWork()_ method if the delegate is set.

### Create the worker and adopt the WorkerDelegate

```swift
class ViewController: UIViewController {

    private let worker = Worker()

    override func viewDidLoad() {
        super.viewDidLoad()

        // It is always important to set the delegate before we invoke the worker to start doing something.
        // Better alternative could be to pass the delegate in the initializer of the Worker.
        worker.delegate = self

        worker.startWork()
    }
}

extension ViewController: WorkerDelegate {

    func didFinishWork() {
        // Worker finished the work. Now we can react to it by fetching some data or updating the UI.
    }
}
```

The _ViewController_ has a **worker** property. In the _viewDidLoad()_ lifecycle method of the _ViewController_, we set the delegate of the worker to _self_, so that when the worker is done it will notify the _ViewController_ instance. After setting the delegate, we invoke the _startWork_() method of the worker and we wait for it to complete to notify us via the _didFinishWork()_ method that we conformed to via _WorkerDelegate_.

I always like to conform to different protocols in the extensions of the classes because it improves the organisation and the readability of the code.

## Examples from UIKit

While working with UIKit we use delegates on daily basis so this is why it is very important to understand this pattern. A good tip for you is when you need to conform to some delegate protocol is to open the protocol definition and see what it has to offer.

Here are a couple of examples:

#### UITableViewDataSource

We use _UITableViewDataSource_ to provide the _UITableView_ with data. A data source object responds to data-related requests from the table. The minimum for every _UITableView_ that we need to do is to provide it with the numbers of rows per section and to provide _UITableViewCell_ for every row. We do that by implementing methods from the _UITableViewDataSource_ protocol:

```swift
// Return the number of rows for the table. We'll assume that the table has only one section.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   return items.count
}

// Provide a cell object for each row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   // Fetch a cell of the appropriate type
   let cell = tableView.dequeueReusableCell(withIdentifier: "cellTypeIdentifier", for: indexPath)

   // Configure the cell using items[indexPath.row]

   return cell
}
```

In this example we can see how the _UITableView_ asks us (the data source delegate) for data that it will display.

#### UITableViewDelegate

With _UITableViewDelegate_ we can react to some interactions with the _UITableView_. In the example below we can override the _didSelectRowAt_ delegate method so that we get notified when user presses the _UITableView_ row.

```swift
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
	// React to the selection of the cell at the indexPath
}
```

_UITableViewDelegate_ can also be used for more advanced _UITableView_ customization.

#### MFMailComposeViewControllerDelegate

If we want to use native system UI and configuration to send an email we can use _MFMailComposeViewController_. We will create the instance of _MFMailComposeViewController_, configure it, adopts its delegate and send the email. The email completion will be delegated to us in the delegate method below that we implemented by overriding _MFMailComposeViewControllerDelegate_:

```swift
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
  // React to mail sending completion
}
```

From here we can see if the email sending was successful or not and react according to that information.

#### UIImagePickerControllerDelegate

If you want to use some images or videos from the Photos app you possibly implemented _UIImagePickerController_ and conformed to its protocol so that you know when the user picked the media files.

```swift
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
  // Use picked images or videos
}
```

## Conclusion

The delegate pattern is very popular in the iOS world and it is very present in UIKit. I like this pattern and I use it in my work but it has some limitations. The communication is always 1-to-1 and that is not practical in some cases so we need to resort to something like an Observer pattern. The amount of code that needs to be added is not small if we are developing something trivial and the testing is harder.

Alternative to using delegates can be passing functions to “_Workers_” and invoking them when we need something or when we want to notify someone. This can result in fewer lines of code but can complicate things if we overuse it. We would also need to be careful not to create retain cycles with this approach.

I hope that this article helped you to understand or to strengthen your knowledge with this pattern.