DEV Community

buddha lama
buddha lama

Posted on

Delegate Design Pattern in Swift

What is the Delegate Design Pattern?

The Delegate Design Pattern is used when one object needs to use another object to perform a task or action. It's like having a personal assistant – you delegate tasks to them, but you're still in charge.

Why Use It?

The beauty of this pattern lies in its ability to tie objects together for specific tasks while keeping them responsible for different things. It's all about teamwork without losing individual identity.

Key Players: Delegator and Delegate

In this pattern, we have two main characters:

The Delegator: This is the object that sends the signal. Think of it as the boss giving orders.
The Delegate: This is the object that receives the signal and performs the action. It's like the employee carrying out the tasks.

The Secret Sauce: Protocols

Now, here's where it gets interesting. The Delegate Pattern often uses protocols (similar to interfaces in Java). These protocols are like a contract between the Delegator and the Delegate.

Why Protocols?

  • Loose Coupling:
    Protocols help in loosely coupling the objects. This means the Delegator and Delegate aren't tightly bound to each other.

  • Limited Access:
    The Delegator only knows about the methods and properties defined in the protocol. It's like giving someone a to-do list without revealing all your secrets.

  • Reusability:
    Can be used in various scenarios with different delegate implementations.

In Practice

Imagine you're building a quiz app. The main quiz controller (Delegator) doesn't need to know how to calculate scores – it just needs to know that it can ask something else to do it. So, it delegates this task to a score calculator (Delegate) through a protocol.

// Protocol for the Score Calculator Delegate
protocol ScoreCalculatorDelegate {
    func calculateScore(for answers: [String]) -> Int
}

// Quiz Controller (Delegator)
class QuizController {
    var delegate: ScoreCalculatorDelegate?
    private let correctAnswers = ["A", "B", "C"]

    func runQuiz() {
        print("Welcome to the Quiz! Please answer A, B, or C for each question.")
        var userAnswers: [String] = []

        for i in 1...3 {
            print("Question \(i): What's your answer?")
            if let answer = readLine() {
                userAnswers.append(answer.uppercased())
            }
        }

        if let score = delegate?.calculateScore(for: userAnswers) {
            print("Quiz completed! Your score is: \(score) out of 3")
        } else {
            print("Quiz completed, but score couldn't be calculated.")
        }
    }
}

// Score Calculator (Delegate)
class SimpleScoreCalculator: ScoreCalculatorDelegate {
    func calculateScore(for answers: [String]) -> Int {
        let correctAnswers = ["A", "B", "C"]
        return zip(answers, correctAnswers).filter { $0 == $1 }.count
    }
}

// Usage
let quizController = QuizController()
let scoreCalculator = SimpleScoreCalculator()
quizController.delegate = scoreCalculator

quizController.runQuiz()
Enter fullscreen mode Exit fullscreen mode

In this example, QuizController doesn't care how the score is calculated. It just knows it can ask its delegate to do it.
Wrapping Up
The Delegate Design Pattern is a fantastic way to keep your code organized, flexible, and maintainable. By separating responsibilities and using protocols, you create a system where objects can work together harmoniously without losing their individual purposes.

Top comments (0)