Delegate in Swift
Introduction to Delegates in Swift
A delegate in Swift is a design pattern that allows one object to communicate with another in a loosely coupled manner. It is widely used in iOS development for handling:
- Custom Callbacks
- TableView & CollectionView Delegation
- Passing Data Between View Controllers
This guide explains Swift Delegates with practical examples.
1. What is a Delegate?
A delegate is a protocol-based communication pattern. It allows a class (delegate) to handle tasks on behalf of another class (delegator).
Key Characteristics of Delegates:
- Uses a protocol to define the communication.
- Assigns a delegate property in the delegating class.
- The delegate class implements the protocol to handle tasks.
2. Creating a Delegate in Swift
Step 1: Define a Protocol
A protocol defines the methods the delegate must implement.
protocol TaskDelegate {
func taskCompleted()
}
Step 2: Create a Delegating Class
This class has a delegate property to call methods from the delegate.
class TaskManager {
var delegate: TaskDelegate? // Weak
reference prevents retain cycles
func startTask() {
print("Task
started")
// Simulating task completion
delegate?.taskCompleted()
}
}
Step 3: Implement the Delegate in Another Class
The class adopting the protocol implements the required method.
class Worker: TaskDelegate {
func taskCompleted() {
print("Task
completed by Worker")
}
}
// Assigning the delegate
let taskManager = TaskManager()
let worker = Worker()
taskManager.delegate = worker
taskManager.startTask()
Output
Task completed by Worker
Loose coupling: TaskManager
does not directly depend on Worker
.
3. Passing Data with Delegates (ViewController Example)
Delegates are commonly used for passing data between view controllers.
Step 1: Define the Delegate Protocol
protocol DataPassingDelegate {
func sendData(_ data: String)
}
Step 2: Assign Delegate in First View Controller
import UIKit
class FirstViewController: UIViewController {
var delegate: DataPassingDelegate?
func sendDataToSecondVC() {
delegate?.sendData("Hello from
FirstViewController")
}
}
Step 3: Implement Delegate in Second View Controller
class SecondViewController: UIViewController,
DataPassingDelegate {
func sendData(_ data: String) {
print("Received
data: \(data)")
}
}
Step 4: Set the Delegate Before Navigation
let firstVC = FirstViewController()
let secondVC = SecondViewController()
firstVC.delegate = secondVC
firstVC.sendDataToSecondVC()
Output
Efficient data transfer between ViewControllers.
4. Using Delegates in UITableView
Delegates are used in UITableView
to handle row selection, scrolling, and cell rendering.
Implementing TableView Delegate Methods
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
view.addSubview(tableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "Row
\(indexPath.row + 1)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected
Row: \(indexPath.row + 1)")
}
}
Output (On Row Selection):
UITableViewDelegate
handles user interactions.
UITableViewDataSource
manages data display.
5. Weak Delegate to Avoid Retain Cycles
Using weak
for the delegate prevents memory leaks.
protocol DownloadDelegate: AnyObject { // Use AnyObject for weak reference
func downloadFinished()
}
class Downloader {
weak var delegate: DownloadDelegate? // Avoids strong reference cycle
func startDownload() {
print("Downloading...")
delegate?.downloadFinished()
}
}
class ViewController: DownloadDelegate {
func downloadFinished() {
print("Download
completed")
}
}
let downloader = Downloader()
let viewController = ViewController()
downloader.delegate = viewController
downloader.startDownload()
weak var delegate
prevents retain cycles.
6. Real-World Use Cases of Delegates
- Handling User Interactions (Button Clicks, TableView Selections)
- Data Transfer Between View Controllers
- Custom UI Component Communication
- Network Callbacks & Background Task Completion
7. When to Use Delegates Over Closures?
Feature | Delegate | Closure |
---|---|---|
Multiple Methods | Best for multiple callbacks | Limited |
Loose Coupling | Decouples classes | Tightly coupled |
Lightweight | No memory overhead | Can cause retain cycles |
Complex Workflows | Better for structured communication | Hard to manage |
Use Delegates for structured multiple callbacks.
Use Closures for one-time execution.
Conclusion
Delegates in Swift provide a powerful and flexible way to communicate between objects. They are widely used in UIKit, data transfer, and event handling.