Swift Language Modello delegato


Esempio

Un delegato è un modello di progettazione comune utilizzato nei framework Cocoa e CocoaTouch, in cui una classe delega la responsabilità di implementare alcune funzionalità a un'altra. Ciò segue un principio di separazione delle preoccupazioni, in cui la classe framework implementa funzionalità generiche mentre un'istanza delegato separata implementa il caso d'uso specifico.

Un altro modo per esaminare il modello delegato è in termini di comunicazione dell'oggetto. Objects spesso bisogno di parlare tra loro e per farlo un oggetto deve essere conforme a un protocol per diventare un delegato di un altro oggetto. Una volta che questa configurazione è stata eseguita, l'altro oggetto torna ai suoi delegati quando accadono cose interessanti.

Ad esempio, una vista nell'interfaccia utente per visualizzare un elenco di dati dovrebbe essere responsabile solo della logica di come vengono visualizzati i dati, non per decidere quali dati devono essere visualizzati.

Facciamo un esempio più concreto. se hai due classi, un genitore e un bambino:

class Parent { }
class Child { }

E vuoi informare il genitore di un cambiamento dal bambino.

In Swift, i delegati vengono implementati usando una dichiarazione di protocol e quindi dichiareremo un protocol che il delegate implementerà. Qui delegato è l'oggetto parent .

protocol ChildDelegate: class {
    func childDidSomething()
}

Il bambino deve dichiarare una proprietà per memorizzare il riferimento al delegato:

class Child {
    weak var delegate: ChildDelegate?
}

Si noti che la variabile delegate è facoltativa e il protocollo ChildDelegate è contrassegnato per essere implementato solo per tipo di classe (senza che la variabile delegate non possa essere dichiarata come riferimento weak evitando qualsiasi ciclo di conservazione. Ciò significa che se la variabile delegate non è più riferito altrove, sarà rilasciato). Questo è così la classe genitore registra solo il delegato quando è necessario e disponibile.

Inoltre, per contrassegnare il nostro delegato come weak , dobbiamo limitare il nostro protocollo ChildDelegate ai tipi di riferimento aggiungendo la parola chiave della class nella dichiarazione del protocollo.

In questo esempio, quando il bambino fa qualcosa e ha bisogno di notificare il suo genitore, il bambino chiamerà:

delegate?.childDidSomething()

Se il delegato è stato definito, al delegato verrà notificato che il bambino ha fatto qualcosa.

La classe genitore dovrà estendere il protocollo ChildDelegate per essere in grado di rispondere alle sue azioni. Questo può essere fatto direttamente sulla classe genitore:

class Parent: ChildDelegate {
    ...

    func childDidSomething() {
        print("Yay!")
    }
}

O utilizzando un'estensione:

extension Parent: ChildDelegate {
    func childDidSomething() {
        print("Yay!")
    }
}

Il genitore deve anche dire al bambino che è il delegato del bambino:

// In the parent
let child = Child()
child.delegate = self

Di default un protocol Swift non consente l'implementazione di una funzione opzionale. Questi possono essere specificati solo se il tuo protocollo è contrassegnato con l'attributo @objc e il modificatore optional .

Ad esempio, UITableView implementa il comportamento generico di una vista tabella in iOS, ma l'utente deve implementare due classi delegate denominate UITableViewDelegate e UITableViewDataSource che implementano l'aspetto e il comportamento delle celle specifiche.

@objc public protocol UITableViewDelegate : NSObjectProtocol, UIScrollViewDelegate {
        
        // Display customization
        optional public func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
        optional public func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
        optional public func tableView(tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int)
        optional public func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
        ...
}

È possibile implementare questo protocollo modificando la definizione della classe, ad esempio:

class MyViewController : UIViewController, UITableViewDelegate

Tutti i metodi non contrassegnati come optional nella definizione del protocollo ( UITableViewDelegate in questo caso) devono essere implementati.