The many well-written existing answers cover the question well, but I'll mention, in some detail, an addition that I believe is worth covering.
The willSet
and didSet
property observers can be used to call delegates, e.g., for class properties that are only ever updated by user interaction, but where you want to avoid calling the delegate at object initialization.
I'll cite Klaas up-voted comment to the accepted answer:
willSet and didSet observers are not called when a property is first initialized. They are only called when the property’s value is set outside of an initialization context.
This is a quite neat as it means e.g. the didSet
property is a good choice of launch point for delegate callbacks & functions, for your own custom classes.
As an example, consider some custom user control object, with some key property value
(e.g. position in rating control), implemented as a subclass of UIView
:
// CustomUserControl.swiftprotocol CustomUserControlDelegate { func didChangeValue(value: Int) // func didChangeValue(newValue: Int, oldValue: Int) // func didChangeValue(customUserControl: CustomUserControl) // ... other more sophisticated delegate functions}class CustomUserControl: UIView { // Properties // ... private var value = 0 { didSet { // Possibly do something ... // Call delegate. delegate?.didChangeValue(value) // delegate?.didChangeValue(value, oldValue: oldValue) // delegate?.didChangeValue(self) } } var delegate: CustomUserControlDelegate? // Initialization required init?(...) { // Initialise something ... // E.g. 'value = 1' would not call didSet at this point } // ... some methods/actions associated with your user control.}
After which your delegate functions can be used in, say, some view controller to observe key changes in the model for CustomViewController
, much like you'd use the inherent delegate functions of the UITextFieldDelegate
for UITextField
objects (e.g. textFieldDidEndEditing(...)
).
For this simple example, use a delegate callback from the didSet
of the class property value
to tell a view controller that one of it's outlets have had associated model update:
// ViewController.swiftImport UIKit// ...class ViewController: UIViewController, CustomUserControlDelegate { // Properties // ... @IBOutlet weak var customUserControl: CustomUserControl! override func viewDidLoad() { super.viewDidLoad() // ... // Custom user control, handle through delegate callbacks. customUserControl = self } // ... // CustomUserControlDelegate func didChangeValue(value: Int) { // do some stuff with 'value' ... } // func didChangeValue(newValue: Int, oldValue: Int) { // do some stuff with new as well as old 'value' ... // custom transitions? :) //} //func didChangeValue(customUserControl: CustomUserControl) { // // Do more advanced stuff ... //}}
Here, the value
property has been encapsulated, but generally: in situations like these, be careful not to update the value
property of the customUserControl
object in the scope of the associated delegate function (here: didChangeValue()
) in the view controller, or you'll end up with infinite recursion.