The delegation pattern is one of the key patterns in the Swift ecosystem, widely used for transferring event handling responsibilities between objects. Delegation allows a class to delegate a part of its behavior to another object (the delegate), typically defined via a protocol.
protocol DataUpdateDelegate: AnyObject { func didUpdateData(_ data: String) } class DataProvider { weak var delegate: DataUpdateDelegate? func updateData() { // ... data update logic delegate?.didUpdateData("New data") } } class ViewController: UIViewController, DataUpdateDelegate { func didUpdateData(_ data: String) { print("Data updated: \(data)") } }
weak (or unowned) to avoid retain cycles.AnyObject to allow weak references.How do you implement delegation if your delegate is a value type (e.g., struct)?
Answer:
In Swift, delegates must be reference types (class or AnyObject), as only reference types are allowed for weak references. A struct or enum cannot act as a delegate, otherwise issues will arise: the compiler will not allow the use of a weak property, and a strong reference will lead to a retain cycle.
// Error! Cannot declare a delegate as a struct: the compiler will not allow it to be weak protocol StructDelegate { ... } struct MyStructDelegate: StructDelegate { ... } weak var delegate: StructDelegate? // Error
Story
In one project, they forgot to mark the delegate property as weak. As a result, a retain cycle occurred between the view and the delegate, causing the application to gradually "inflate" in memory and crash after half an hour of operation.
Story
The delegate was implemented as a value type (struct) instead of a class. The IBOutlet that was supposed to be the delegate did not receive notifications — the connection did not occur at all. The problem was discovered only after analyzing logs and debugging.
Story
In the project, the delegate protocol did not inherit from AnyObject, but the delegate property was declared as weak var. This led to a compiler error that took the team some time to understand and fix.