Per capire delegates
, devi capire protocols
.
Un protocol
è come un contratto di servizio. Quando un oggetto (più spesso una sottoclasse UIViewController
, ma non sempre) firma quel contratto, sta dicendo "Sono interessato a fornire la logica per supportare il messaggio che mi mandi". Questo è simile a NSNotificationCenter
per quanto riguarda la registrazione per un livello di interesse, la differenza essendo un oggetto che utilizza la delega può avere solo un delegate
alla volta, dove più oggetti possono registrarsi per lo stesso NSNotification
.
Apple utilizza la delega in modo pervasivo. Sempre di più, però, stai vedendo che Apple trasferisce molte delle API a blocks
, che sono simili a callbacks
in altre lingue.
Detto questo, la delega aiuta a mantenere MVC, anche se direi che la delega è un modello di progettazione in sé e per sé. Aiuta a separare i modelli dai controllori. Come nell'esempio di John Cartwright, un UITableView
sa come visualizzare righe e sezioni. Sa come riutilizzare UITableViewCells
per motivi di prestazioni. Conosce tutte le altre cose che un UIScrollView
conosce. Ma non sa quali celle da visualizzare. Non sa cosa popolare con queste celle. Non sa quali celle da riutilizzare per un dato NSIndexPath
. Questo dovrebbe essere il compito del controller, comunque. La delega consente alla vista tabella di scaricare questa logica senza vista su un oggetto che dovrebbe comunque avere quella responsabilità.
Inoltre, non sei bloccato in un delegato per l'intera vita di un oggetto. Puoi facilmente avere più origini dati per un dato UITableView
e cambiarle in base al tempo di esecuzione, se necessario.
Quindi, da un lato, la delega è ottima per fornire dati e rispondere alle interazioni da un oggetto. Lo vedrai in molte classi UIKit, ad esempio UITableView
, UIPickerView
, UICollectionView
, ecc.
Ma la delega è anche molto utile quando si desidera passare le informazioni tra gli oggetti. Puoi facilmente creare i tuoi protocolli e iscrivere i tuoi oggetti per seguirli. Inoltre, i metodi di protocollo sono @required
per impostazione predefinita, ma è possibile specificare alcuni metodi come @optional
. Questo può darti una certa flessibilità se ne hai bisogno. Supponiamo che tu abbia un controller di visualizzazione genitore e un controller di visualizzazione figlio. Forse stai usando la nuova API di Containment per farlo. In genere, se è necessario passare le informazioni dal genitore al figlio, lo si fa con una proprietà. Fatto. Ma cosa succede se è necessario passare le informazioni dal bambino al genitore? Forse qualcosa cambia nel bambino e devi avvisare il genitore. Certo, potresti fare qualche KVO su certi valori. Ma forse vuoi sapere quando viene premuto un pulsante. Basta creare un nuovo protocollo nel controller della vista figlio
@protocol MyChildDelegate
- (void)buttonWasTappedInChild:(MyChildViewController *)childViewController;
@end
@interface MyChildViewController : UIViewController
@property (weak, nonatomic) id <MyChildDelegate> delegate;
@end
In MyChildViewController, quando il tuo pulsante viene toccato, controlla semplicemente se il tuo delegato risponde al messaggio delegato (se è richiesto e il tuo delegato non implementa il metodo, andrai in crash. Puoi rendere il metodo @optional
se è necessario) e inviarlo:
- (IBAction)someButtonTapped:(id)sender {
if ([self.delegate respondsToSelector:@selector(buttonWasTappedInChild:)]) {
[self.delegate buttonWasTappedInChild:self];
}
}
Quindi imposta il delegato di MyChildViewController su self
e implementa - (void)buttonWasTappedInChild:(MyChildViewController *)childViewController
nel tuo controller di visualizzazione padre. BOOM! Hai informazioni passate da un bambino fino al genitore. La relazione tra i due oggetti non ha nemmeno bisogno di essere il più vicino come genitore / figlio. È un contratto di servizio, quindi finché l'oggetto che si registra accetta la sua parte dell'accordo, implementando i metodi richiesti, sei d'oro!
NOTA: i delegati dovrebbero essere deboli / assegnare le proprietà, altrimenti entrerai in un ciclo di conservazione in cui nessuno dei due oggetti può essere deallocato.
Spero che questo aiuti!