Diseño de software

Delegate vs Observer en Swift: comparación completa para saber cuál usar

Al desarrollar para iOS, el patrón Delegate aparece constantemente.

4 min de lectura
Imagen de portada de Delegate vs Observer en Swift: comparación completa para saber cuál usar

Al desarrollar para iOS, el patrón Delegate aparece constantemente.

Cada vez que trabajas con UITableView o UITextField, añades un delegate y quizá te preguntas: «¿Por qué un delegate? ¿No bastaría con un closure o una notificación?»

Después de aprender el patrón Observer, la confusión puede aumentar. Ambos avisan cuando ocurre algo, pero ¿cuál es exactamente la diferencia?

Empecemos por la conclusión.

Un delegate es una comunicación 1:1 en la que un objeto delega algo a un único destinatario: «Esto te lo dejo a ti».

Un observer es una difusión 1:N en la que varias personas se suscriben simultáneamente a un evento.

Con esa frase ya tienes la mitad entendida. Hoy aclararemos la diferencia con código.


¿Qué es el patrón Delegate?

Delegate significa «delegación».

Consiste en entregar una tarea difícil de gestionar directamente a un objeto de confianza: «Decídelo tú por mí».

Veamos una analogía de la vida real.

Quiero reservar un restaurante, pero me da pereza llamar, así que se lo pido a un asistente: «Haz la reserva por mí».

Ese asistente es el delegate. Una persona pide y otra recibe la petición. Exactamente 1:1.

En Swift, esta relación se define mediante un protocolo.

// Definir en un protocolo el trabajo delegado
protocol OrderDelegate: AnyObject {
    func didFinishOrder(_ menu: String)
}

class Restaurant {
    weak var delegate: OrderDelegate?  // Designar a una sola persona
    func order(_ menu: String) {
        delegate?.didFinishOrder(menu)  // Notificar únicamente a esa persona
    }
}

Lo importante es que delegateno es un array, sino una única propiedad.

Como solo se delega a una persona, naturalmente se almacena una sola. Esa es la razón de que Delegate sea 1:1.

También aparece weak. Las referencias fuertes pueden crear un retain cycle y provocar una fuga de memoria, por lo que los delegates suelen mantenerse como referencias weak.


¿En qué se diferencia del patrón Observer?

Observer significa «observador».

Cuando ocurre un evento, se envía una notificación a varios observadores de una sola vez.

Continuemos con la analogía del asistente.

Esta vez difundo por el barrio la noticia de la apertura del restaurante: «¡Abrimos esta tarde!»

Puede haber diez oyentes o cien. No me importa quién escucha; simplemente difundo el mensaje.

Eso es una difusión 1:N: el patrón Observer.

En iOS, NotificationCenteres el ejemplo más representativo.

// Ocurre un evento → se difunde a todos los suscriptores
NotificationCenter.default.post(name: .storeOpen, object: nil)

// Los objetos interesados se suscriben por separado
NotificationCenter.default.addObserver(
    self, selector: #selector(handleOpen),
    name: .storeOpen, object: nil)

El emisor no sabe quién lo recibe. Solo añade un nombre y lo envía.

Los receptores también se suscriben por separado, aunque sean varios.

Como no necesitan conocerse, el acoplamiento es bajo; la desventaja es que cuesta rastrear quién escucha actualmente la notificación.

Al escribir el código directamente, por fin lo entendí
Al escribir el código directamente, por fin lo entendí

Delegate vs Observer de un vistazo

Explicarlo solo con palabras puede confundir, así que lo resumí en una tabla.

La delegación 1:1 y la difusión 1:N quedan claras en un diagrama
La delegación 1:1 y la difusión 1:N quedan claras en un diagrama
Categoría Delegate Observer
Comunicación 1:1 (delegación a uno) 1:N (difusión a varios)
¿Conoce a la otra parte? Se conocen claramente No necesitan conocerse
Ejemplo representativo UITableViewDelegate NotificationCenter
Respuesta (valor de retorno) Fácil de recibir Difícil de recibir
Acoplamiento Relativamente alto Bajo
Seguimiento/depuración Fácil Algo difícil

La clave es: «¿Necesitas recibir una respuesta?»

Con Delegate, preguntas «¿Qué altura debe tener esta celda?» y la otra parte devuelve un valor. Es una estructura bidireccional.

Observer solo envía y termina. Al emisor no le interesa cómo responde nadie.


Entonces, ¿cuándo conviene usar cada uno?

Estos son los criterios que establecí al usarlos en proyectos reales.

Cuándo usar Delegate

  1. Cuando solo necesitas comunicarte con un objeto
  2. Cuando necesitas recibir un valor (por ejemplo, cantidad o altura de celdas)
  3. Cuando el orden y el flujo son claros, como en las transiciones de pantalla

Cuándo usar Observer

  1. Cuando varias pantallas deben reaccionar simultáneamente a un evento
  2. Para eventos globales de la app, como cambios en el estado de inicio de sesión o el modo oscuro
  3. Cuando el emisor y los receptores no necesitan conocerse

Por ejemplo, si la pantalla de inicio, la página de perfil y el banner superior deben cambiar al iniciar sesión, Delegate se queda corto.

Como solo delega a una persona, conectar las tres partes ensucia el código.

En ese caso, es mucho más limpio difundir una vez «¡Has iniciado sesión!» mediante Observer.

En cambio, una situación 1:1 como «Se pulsó el botón de confirmación del campo de entrada» requiere un delegate o un closure.

Dibujarlo con flechas en una pizarra lo hace mucho más fácil
Dibujarlo con flechas en una pizarra lo hace mucho más fácil

Resumen

Aunque parezcan similares, basta con pensar «¿a cuántas personas hay que avisar?» para elegir.

Una persona: Delegate; varias personas: Observer. Con recordar esta regla es suficiente.

Prueba a aplicar lo aprendido la próxima vez que escribas código. Cuando lo que solo conocías en teoría se vuelve natural al programar, los patrones resultan mucho más fáciles. ¡Ánimo!

Seguir leyendo