Delegation In Detail

abdul ahad
5 min readMar 28, 2024

--

Photo by Connor Coyne on Unsplash

Delegate pattern

Delegation is defined as passing responsibility for the behavior implementation from one instance to another.

When an instance delegates some of its behavior, it speaks: “I don’t know how to implement this method. Please do it for me”.

In this pattern, the delegating object (the delegate) has a reference to another object (the delegate object) and calls methods on it to inform it about events or to ask for information.

Simple Example

Suppose we have a Person class that represents a person with a name. We want to delegate the responsibility of greeting the person to another object.

First, let’s define a protocol called GreetingDelegate:


protocol GreetingDelegate {
func greet(name: String)
}

Next, let’s create the Person class:

// Person is Delegating object
class Person {
let name: String
var delegate: GreetingDelegate?

init(name: String) {
self.name = name
}

//delegating object callls delegate
func sayHello() {
delegate?.greet(name: name)
}
}

In the Person class, we declare a name property to hold the name of the person and a delegate property of type GreetingDelegate?. When the sayHello() method is called, the person notifies the delegate by calling the greet(name:) method.

Now, let’s create a class that acts as the delegate:

// delegate object
class Greeter: GreetingDelegate {
func greet(name: String) {
print("Hello, \(name)!")
}
}
  • We create instances of Person and Greeter classes.
  • We assign the Greeter instance as the delegate of the Person instance by setting the delegate property.
  • When the sayHello() method is called on the Person, it notifies the Greeter delegate by calling the greet(name:) method, and the greeter prints "Hello, Abdul!" to the console.
let person = Person(name: "Abdul")
let greeter = Greeter()

// Assign the greeter as the delegate of the person
person.delegate = greeter

// When the person wants to say hello
person.sayHello()

Why do we need a delegate?

Delegation is a great tool for object composition, which is an alternative to inheritance. it helps decouple class from concrete behavior thus allowing polymorphism so clients can implement their own behavior into the framework. UITableview is a prime example from UIKit which provides abstractions in the form of UITableviewDelegate and UITableViewDataSource and we as clients provide the implementation so it’s up to us to provide the behaviour.

let us take the example above we injected greeting behaviour into the person class.

however, we can also have other behaviors using polymorphism for the person class.

so to prevent person class from being coupled with the specific implementations we use the delegate to make it possible to have many implementations.

UIKit Example

Similarly preventing table view from being coupled with specific implementation table view delegates and data sources makes it possible to have many implementations to get different behaviours which depends on your implementations of these delegate and data source methods.

UITableView and its abstractions live in their own module which we call UIKit which is hidden from us by Apple. However, the implementations of these abstractions live in our module or app. Let’s take a simple example.

MyTableViewController conforms to the UITableViewDataSource and UITableViewDelegate and provides its own implementations of datasource and delegate methods

class MyTableViewController: UIViewController {
// UITableView instance
let tableView = UITableView()

// Data source
let items = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]

override func viewDidLoad() {
super.viewDidLoad()

// Setup table view
tableView.frame = view.bounds
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
}
}

// MARK: - UITableViewDataSource

extension MyTableViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = items[indexPath.row]
return cell
}
}

// MARK: - UITableViewDelegate

extension MyTableViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected item: \(items[indexPath.row])")
}
}

MyTableviewcontroller provides it’s own implementation while someother class may provide it’s own implementation so apple made tableview in a way that we as clients can provide our own behaviour using our own implementation . imagine if tableview delegate and datasource were tied to a concrete type.

Benefits

Delegation is a powerful design pattern in iOS development that offers several benefits:

  1. Decoupling and Separation of Concerns: Delegation helps in separating responsibilities between objects. By delegating tasks to another object, you create a clean separation of concerns, where each object has a single responsibility.
  2. Reuse and Composition: Delegation promotes code reuse by allowing the same class to be reused in different contexts with different behaviors provided by different delegates. It encourages composition over inheritance, as behavior can be composed dynamically at runtime.
  3. Loose Coupling: Delegation promotes loose coupling between objects. The delegate object does not need to know the internal details of the delegating object, reducing dependencies and making the codebase more modular and easier to maintain.
  4. Testability: Delegation simplifies unit testing by enabling the use of mock objects for testing. Mocking the delegate object allows for isolated testing of the delegating object’s behavior, making it easier to write unit tests with predictable results.
  5. Event Handling: Delegation is commonly used for event handling in iOS development. UI controls like buttons, table views, and collection views use delegation to notify their delegates of user interactions or state changes, enabling custom responses to these events.

--

--

abdul ahad
abdul ahad

Written by abdul ahad

A software developer dreaming to reach the top and also passionate about sports and language learning

No responses yet