Swift Language Patrón de delegado


Ejemplo

Un delegado es un patrón de diseño común utilizado en los marcos de Cocoa y CocoaTouch, donde una clase delega la responsabilidad de implementar alguna funcionalidad a otra. Esto sigue un principio de separación de preocupaciones, donde la clase marco implementa una funcionalidad genérica mientras que una instancia delegada separada implementa el caso de uso específico.

Otra forma de ver el patrón de delegado es en términos de comunicación de objetos. Objects menudo necesitan conversar entre ellos y para hacerlo, un objeto debe ajustarse a un protocol para convertirse en un delegado de otro Objeto. Una vez que se ha realizado esta configuración, el otro objeto responde a sus delegados cuando suceden cosas interesantes.

Por ejemplo, una vista en la interfaz de usuario para mostrar una lista de datos debe ser responsable solo de la lógica de cómo se muestran los datos, no de decidir qué datos deben mostrarse.

Vayamos a un ejemplo más concreto. Si tienes dos clases, un padre y un niño:

class Parent { }
class Child { }

Y desea notificar a los padres de un cambio del niño.

En Swift, los delegados se implementan utilizando una declaración de protocol por lo que declararemos un protocol que implementará el delegate . Aquí el delegado es el objeto parent .

protocol ChildDelegate: class {
    func childDidSomething()
}

El niño debe declarar una propiedad para almacenar la referencia al delegado:

class Child {
    weak var delegate: ChildDelegate?
}

Observe la variable delegate es un opcional y el protocolo ChildDelegate está marcado sólo a ser implementado por tipo de clase (sin esto el delegate variable no puede ser declarada como una weak referencia evitando cualquier ciclo conservan. Esto significa que si el delegate la variable ya no es referenciado en cualquier otro lugar, será lanzado). Esto es para que la clase padre solo registre al delegado cuando sea necesario y esté disponible.

También para marcar a nuestro delegado como weak , debemos restringir nuestro protocolo ChildDelegate a tipos de referencia agregando palabras clave de class en la declaración de protocolo.

En este ejemplo, cuando el niño hace algo y necesita notificar a su padre, el niño llamará:

delegate?.childDidSomething()

Si el delegado ha sido definido, se le notificará al delegado que el niño ha hecho algo.

La clase principal deberá extender el protocolo ChildDelegate para poder responder a sus acciones. Esto se puede hacer directamente en la clase padre:

class Parent: ChildDelegate {
    ...

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

O usando una extensión:

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

El padre también debe decirle al niño que es el delegado del niño:

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

Por defecto, un protocol Swift no permite implementar una función opcional. Solo se pueden especificar si su protocolo está marcado con el atributo @objc y el modificador optional .

Por ejemplo, UITableView implementa el comportamiento genérico de una vista de tabla en iOS, pero el usuario debe implementar dos clases delegadas llamadas UITableViewDelegate y UITableViewDataSource que implementan el aspecto y el comportamiento de las células específicas.

@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)
        ...
}

Puede implementar este protocolo cambiando su definición de clase, por ejemplo:

class MyViewController : UIViewController, UITableViewDelegate

Se debe implementar cualquier método que no esté marcado como optional en la definición de protocolo ( UITableViewDelegate en este caso).