Delegate: qué es, patrón de delegación y protocolos iOS

Autor: IT Sectr Publicado: 2026-02-17 Tiempo de lectura: 9 min

Delegate es un patrón de diseño donde un objeto delega la ejecución de una tarea a otro objeto. En iOS, el patrón se implementa mediante protocolos Swift y @protocol Objective-C. La delegación es uno de los patrones fundamentales de Cocoa Touch, utilizado en UITableViewDelegate, UITextFieldDelegate y cientos de otras API de Apple. Según Apple Developer Documentation (2025), alrededor del 70% de las clases del sistema UIKit utilizan delegados para personalizar el comportamiento sin herencia.

Puntos clave

  • Delegate — un patrón donde el objeto A delega la ejecución de una tarea al objeto B a través de un protocolo o interfaz
  • Protocolo Swift define un conjunto de métodos que el delegado puede o debe implementar
  • Referencia débil al delegado es obligatoria para prevenir ciclos de retención y fugas de memoria
  • UITableViewDelegate — el ejemplo más común de delegado en iOS con más de 20 métodos opcionales
  • Diferencia con Observer: el delegado es una relación 1:1, mientras que las notificaciones funcionan bajo el principio 1:N

¿Qué es el patrón Delegate?

Delegate es un patrón de diseño de comportamiento que permite a un objeto delegar parte de sus responsabilidades a otro objeto. A diferencia de la herencia, donde una clase hija sobrescribe los métodos del padre, el delegado utiliza composición: el objeto propietario mantiene una referencia al delegado y llama a sus métodos en puntos específicos.

El delegado define un protocolo — un conjunto de métodos que el delegado puede implementar. Los métodos se dividen en obligatorios y opcionales. En Swift, los métodos opcionales del protocolo se marcan con la palabra clave @objc optional.

Cómo funciona el delegado

El objeto A (propietario) contiene una propiedad delegate — una referencia débil al objeto B (delegado). Cuando ocurre un evento, A verifica si B implementa el método correspondiente del protocolo y lo llama. La referencia débil es obligatoria: sin ella, el delegado no puede ser liberado de la memoria porque el propietario lo retiene con una referencia fuerte.

Swift
protocol LoaderDelegate: AnyObject {
    func loaderDidStart(_ loader: DataLoader)
    func loader(_ loader: DataLoader, didLoad data: Data)
    func loader(_ loader: DataLoader, didFailWith error: Error)
}

class DataLoader {
    weak var delegate: LoaderDelegate?
    
    func start() {
        delegate?.loaderDidStart(self)
        // carga asíncrona
    }
}

La clase DataLoader define el protocolo LoaderDelegate y llama a los métodos del delegado en puntos clave del ciclo de carga. AnyObject garantiza que el protocolo solo puede ser implementado por clases — esto es necesario para la referencia débil.

¿Cómo funciona Delegate en Swift?

La implementación del delegado en Swift incluye tres pasos: declarar el protocolo, crear una propiedad delegate débil en el propietario e implementar el protocolo en la clase delegada. Veamos un ejemplo de un UITextField personalizado con validación.

Swift
protocol ValidatorDelegate: AnyObject {
    func validate(_ input: String) -> Bool
    func validatorDidFail(_ input: String)
}

class ValidatedTextField: UITextField {
    weak var validator: ValidatorDelegate?
    
    override func textDidChange() {
        guard let text = self.text else { return }
        if validator?.validate(text) == false {
            validator?.validatorDidFail(text)
            self.layer.borderColor = UIColor.red.cgColor
        }
    }
}

class LoginViewController: UIViewController, ValidatorDelegate {
    let textField = ValidatedTextField()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textField.validator = self
    }
    
    func validate(_ input: String) -> Bool {
        return input.count >= 6
    }
    
    func validatorDidFail(_ input: String) {
        print("Validación fallida: entrada demasiado corta")
    }
}

LoginViewController implementa el protocolo ValidatorDelegate y se asigna como delegado de textField. Con cada cambio de texto, ValidatedTextField llama a validate(_:), y si la validación falla — validatorDidFail(_:). El controlador actúa como intermediario entre la Vista y la lógica de validación.

Delegate vs NotificationCenter vs Closure

La elección entre delegado, notificaciones y closures depende del número de receptores y el acoplamiento de componentes. Cada mecanismo resuelve el problema de comunicación entre objetos, pero con diferentes compromisos.

CaracterísticaDelegateNotificationCenterClosure
Tipo de comunicación1:11:N1:1
AcoplamientoDébil (mediante protocolo)Muy débil (clave de cadena)Medio (captura de contexto)
Seguridad de tiposCompletaNinguna (Any?)Completa
Riesgo de ciclo de retenciónNo (weak)NoSí (captura de self)
Cuándo usarCallbacks complejos con múltiples métodosEventos que interesan a muchosClosures simples con 1-2 callbacks

Delegate es óptimo cuando necesitas pasar una serie de eventos relacionados a un solo receptor. NotificationCenter es mejor para notificaciones de difusión. Closure es para operaciones asíncronas simples, como los completion handlers en URLSession.

Implementación de Delegate en Objective-C

Objective-C utiliza @protocol y @optional para declarar delegados. A diferencia de Swift, todos los métodos del protocolo son opcionales por defecto. La diferencia clave es la llamada respondsToSelector: antes de enviar un mensaje al delegado, ya que el método puede no estar implementado.

Objective-C
@protocol ImageCacheDelegate 
@optional
- (void)cacheDidStartDownload: (ImageCache *)cache;
- (void)cache: (ImageCache *)cache didCacheImage: (UIImage *)image;
@required
- (void)cache: (ImageCache *)cache didFailWithError: (NSError *)error;
@end

@interface ImageCache : NSObject
@property (nonatomic, weak) id<ImageCacheDelegate> delegate;
- (void)downloadImageAtURL: (NSURL *)url;
@end

@implementation ImageCache
- (void)downloadImageAtURL: (NSURL *)url {
    if ([self.delegate respondsToSelector:@selector(cacheDidStartDownload:)]) {
        [self.delegate cacheDidStartDownload:self];
    }
    // carga asíncrona de imagen
}
@end

La diferencia clave en Objective-C: antes de llamar a un método opcional, es necesaria una verificación de respondsToSelector:. En Swift, los métodos opcionales del protocolo eliminan esta verificación — el optional chaining (?.) maneja automáticamente la ausencia de implementación.

Errores comunes al trabajar con delegados

Los errores en el uso de delegados provocan fugas de memoria, caídas de la aplicación y errores no evidentes. Veamos los cinco problemas más comunes.

Referencia fuerte al delegado

El ciclo de retención es el error más común. Si la propiedad delegate se declara como strong, y el delegado a su vez posee el objeto propietario, se forma un ciclo de retención. Ambos objetos nunca serán liberados de la memoria. Solución: declarar siempre el delegado como weak var en Swift o @property (weak) en Objective-C.

Delegado no anulado después de dealloc

Si el objeto propietario sobrevive al delegado y la referencia permanece, llamar al método del delegado provocará EXC_BAD_ACCESS. La referencia débil resuelve este problema automáticamente: después de que el delegado se libera, la propiedad se vuelve nil. Sin embargo, en escenarios multiproceso, se debe verificar adicionalmente al delegado en el hilo principal.

Número excesivo de métodos en el protocolo

Un protocolo con más de 20 métodos viola el Principio de Segregación de Interfaces (ISP). UITableViewDelegate contiene alrededor de 30 métodos opcionales — esta es una excepción histórica. En tus propios protocolos, es mejor dividir la responsabilidad en varios protocolos más pequeños, cada uno con su propio rol.

Ejemplos de Delegate en API de sistema iOS

Las API del sistema Apple utilizan activamente el patrón Delegate. Veamos tres ejemplos clave de UIKit que aparecen en cada aplicación iOS.

APIProtocoloMétodos clave
UITableViewUITableViewDelegatedidSelectRowAt, heightForRowAt, willDisplay
UITextFieldUITextFieldDelegateshouldChangeCharactersIn, didBeginEditing, shouldReturn
URLSessionURLSessionDelegatedidReceiveChallenge, didCompleteWithError, didBecomeInvalidWithError

Cada uno de estos protocolos implementa diferentes aspectos del comportamiento: UITableViewDelegate gestiona la apariencia y la respuesta al tacto, UITextFieldDelegate controla la entrada de texto, URLSessionDelegate maneja eventos de red. Esto demuestra la flexibilidad del patrón: el delegado puede adaptarse a cualquier área de responsabilidad.

Preguntas frecuentes

¿Cuál es la diferencia entre delegate y dataSource en iOS?

Delegate gestiona el comportamiento y la apariencia (altura de celda, respuesta al tacto). DataSource proporciona datos (número de filas, contenido de celdas). En UITableViewDelegate y UITableViewDataSource — son dos protocolos separados que dividen la responsabilidad entre presentación y datos.

¿Por qué delegate se declara como weak?

La referencia débil previene los ciclos de retención. El propietario (por ejemplo, UITableView) mantiene una referencia al delegado solo como weak. Si el delegado (UIViewController) posee la tabla, una referencia fuerte al delegado crearía un ciclo: ViewController → UITableView → Delegate (ViewController). Weak rompe este ciclo.

¿Se puede usar delegate en SwiftUI?

En SwiftUI, el patrón Delegate se usa con menos frecuencia — se reemplaza por @Binding, @State y closures. Sin embargo, el delegado todavía se utiliza para la integración con UIKit a través de UIViewRepresentable. Por ejemplo, MKMapViewDelegate y WKUIDelegate siguen siendo relevantes al envolver componentes UIKit en SwiftUI.

¿Qué es @objc optional en los protocolos Swift?

@objc optional permite declarar métodos opcionales en un protocolo Swift. Este es un mecanismo de compatibilidad con el runtime de Objective-C. Sin @objc, todos los métodos del protocolo Swift son obligatorios por defecto. Optional se utiliza en protocolos UIKit donde el delegado puede implementar solo los métodos que necesita.

¿Cuántos delegados puede tener un objeto?

Un objeto puede tener solo un delegado para cada propiedad delegate. Si necesitas notificar a múltiples objetos, usa multicast delegate, un array de delegados o NotificationCenter. El patrón Delegate está diseñado originalmente como una relación 1:1.

Resumen

  • Delegate — un patrón de diseño de comportamiento que transfiere la ejecución de una tarea de un objeto a otro mediante un protocolo
  • Protocolo Swift declara un conjunto de métodos; los métodos opcionales se marcan con @objc optional, los obligatorios siempre se implementan
  • Referencia débil al delegado es obligatoria para prevenir ciclos de retención y fugas de memoria
  • UITableViewDelegate es el ejemplo más conocido; sus métodos gestionan la altura, selección y visualización de las celdas
  • Delegate se diferencia de NotificationCenter por una relación 1:1 frente a 1:N y seguridad completa de tipos
  • Objective-C requiere la verificación respondsToSelector: para métodos opcionales, Swift lo maneja automáticamente
  • Recomendación: usa delegate para callbacks complejos con múltiples métodos relacionados y closure para cierres simples

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también