Le molte risposte esistenti ben scritte coprono bene la domanda, ma menzionerò, in alcuni dettagli, un'aggiunta che credo valga la pena di essere trattata.
Gli osservatori proprietà willSet
e didSet
possono essere utilizzati per chiamare delegati, ad esempio, per le proprietà di classe che vengono sempre aggiornate solo dall'interazione dell'utente, ma dove si desidera evitare di chiamare il delegato all'inizializzazione dell'oggetto.
Citerò il commento di Klaas votato alla risposta accettata:
Gli osservatori willSet e didSet non vengono chiamati quando una proprietà viene inizializzata per la prima volta. Vengono chiamati solo quando il valore della proprietà è impostato al di fuori di un contesto di inizializzazione.
Questo è piuttosto accurato in quanto significa, ad esempio, la didSet
proprietà è una buona scelta di punto di avvio per callback e funzioni delegate, per le tue classi personalizzate.
Ad esempio, si consideri un oggetto di controllo utente personalizzato, con alcune proprietà chiave value
(ad es. Posizione nel controllo di classificazione), implementato come sottoclasse di UIView
:
// CustomUserControl.swift
protocol 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.
}
Dopo di che le funzioni del delegato possono essere utilizzate, ad esempio, in alcuni controller di visualizzazione per osservare le modifiche chiave nel modello CustomViewController
, proprio come se si utilizzassero le funzioni delegate intrinseche degli oggetti UITextFieldDelegate
for UITextField
(ad es textFieldDidEndEditing(...)
.).
Per questo semplice esempio, utilizzare un callback delegato dalla didSet
proprietà della classe value
per dire a un controller di visualizzazione che uno dei suoi punti vendita ha avuto un aggiornamento del modello associato:
// ViewController.swift
Import 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 ...
//}
}
Qui, la value
proprietà è stata incapsulata, ma in generale: in situazioni come queste, fai attenzione a non aggiornare la value
proprietà customUserControl
dell'oggetto nell'ambito della funzione delegata associata (qui:) didChangeValue()
nel controller di visualizzazione, o finirai con ricorsione infinita.
get
&set
) devono fondamentalmente avere una proprietà calcolata sulla base di un'altra proprietà, ad esempio convertendo un'etichettatext
in un annoInt
.didSet
ewillSet
siamo qui per dire ... ehi, questo valore è stato impostato, ora facciamolo, ad es. Il nostro dataSource è stato aggiornato ... quindi ricarichiamo tableView in modo che includa nuove righe. Per un altro esempio, vedi la risposta di dfri su come chiamare i delegatididSet