Delegate: ce este, modelul de delegare și protocoalele iOS

Autor: IT Sectr Publicat: 2026-02-17 Timp de citire: 9 min

Delegate — este un model de proiectare în care un obiect delegă executarea unei sarcini altui obiect. În iOS, modelul este implementat prin protocoale Swift și @protocol Objective-C. Delegation este unul dintre modelele fundamentale ale Cocoa Touch, utilizat în UITableViewDelegate, UITextFieldDelegate și sute de alte API-uri Apple. Conform Apple Developer Documentation (2025), aproximativ 70% din clasele de sistem UIKit folosesc delegați pentru personalizarea comportamentului fără moștenire.

Principalele

  • Delegate — modelul în care obiectul A delegă executarea sarcinii obiectului B printr-un protocol sau interfață
  • Protocolul Swift definește un set de metode pe care delegatul le poate sau trebuie să le implementeze
  • Referința weak către delegat este obligatorie pentru a preveni retain cycle și scurgerile de memorie
  • UITableViewDelegate — cel mai comun exemplu de delegat în iOS cu 20+ metode opționale
  • Diferența de Observer: delegatul are o relație 1:1, în timp ce notificările funcționează pe principiul 1:N

Ce este modelul Delegate?

Delegate — este un model de proiectare comportamentală care permite unui obiect să transfere o parte din responsabilitățile sale altui obiect. Spre deosebire de moștenire, unde clasa copil suprascrie metodele părintelui, delegatul folosește compoziția: obiectul-proprietar stochează o referință către delegat și apelează metodele acestuia în puncte specifice.

Delegatul definește un protocol — un set de metode pe care delegatul le poate implementa. Metodele sunt împărțite în obligatorii (required) și opționale (optional). În Swift, metodele opționale ale protocolului sunt marcate cu cuvântul cheie @objc optional.

Principiul de funcționare al delegatului

Obiectul A (proprietarul) conține proprietatea delegate — o referință weak către obiectul B (delegatul). Când are loc un eveniment, A verifică dacă B implementează metoda corespunzătoare a protocolului și o apelează. Referința weak este obligatorie: fără ea, delegatul nu poate fi eliberat din memorie, deoarece proprietarul îl menține cu o referință strong.

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)
        // încărcare asincronă
    }
}

Clasa DataLoader definește protocolul LoaderDelegate și apelează metodele delegatului în punctele cheie ale ciclului de viață al încărcării. AnyObject garantează că protocolul poate fi implementat doar de clase — acest lucru este necesar pentru referința weak.

Cum funcționează Delegate în Swift?

Implementarea delegatului în Swift include trei pași: declararea protocolului, crearea proprietății weak delegate în proprietar și implementarea protocolului în clasa-delegat. Să analizăm pe exemplul unui UITextField personalizat cu validare.

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("Validare eșuată: intrare prea scurtă")
    }
}

LoginViewController implementează protocolul ValidatorDelegate și se setează ca delegat al textField. La fiecare modificare a textului, ValidatedTextField apelează validate(_:), iar dacă validarea eșuează — validatorDidFail(_:). Controller acționează ca intermediar între View și logica de validare.

Delegate vs NotificationCenter vs Closure

Alegerea între delegat, notificări și closure-uri depinde de numărul de destinatari și gradul de cuplare al componentelor. Fiecare mecanism rezolvă problema comunicării între obiecte, dar cu compromisuri diferite.

CaracteristicăDelegateNotificationCenterClosure
Tipul legăturii1:11:N1:1
CuplareSlabă (prin protocol)Foarte slabă (cheie-string)Medie (capturarea contextului)
Siguranța tipurilorCompletăLipsește (Any?)Completă
Risc retain cycleNu (weak)NuDa (capturarea self)
Când se aplicăCallback-uri complexe cu mai multe metodeEvenimente care interesează pe mulțiClosure-uri simple cu 1-2 callback-uri

Delegate este optim când trebuie transmisă o serie de evenimente conexe unui singur destinatar. NotificationCenter este mai bun pentru notificări de tip broadcast. Closure — pentru operații asincrone simple, cum ar fi completion handler în URLSession.

Implementarea Delegate în Objective-C

Objective-C folosește @protocol și @optional pentru declararea delegaților. Spre deosebire de Swift, toate metodele protocolului sunt implicit opționale. Diferența cheie — apelul respondsToSelector: înainte de a trimite un mesaj delegatului, deoarece metoda poate să nu fie implementată.

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];
    }
    // încărcare asincronă a imaginii
}
@end

Diferența cheie în Objective-C: înainte de apelarea unei metode opționale este necesară verificarea respondsToSelector:. În Swift, metodele opționale ale protocolului elimină această verificare — optional chaining (?.) gestionează automat cazul lipsei implementării.

Erori tipice la lucrul cu delegații

Erorile de utilizare a delegaților duc la scurgeri de memorie, crash-uri ale aplicației și bug-uri neevidente. Să analizăm cinci dintre cele mai frecvente probleme.

Referința strong la delegat

Retain cycle — cea mai frecventă eroare. Dacă proprietatea delegate este declarată ca strong, iar delegatul la rândul său deține obiectul-proprietar, se formează un ciclu de reținere. Ambele obiecte nu vor fi niciodată eliberate din memorie. Soluție: declarați întotdeauna delegatul ca weak var în Swift sau @property (weak) în Objective-C.

Delegatul nu este anulat după dealloc

Dacă obiectul-proprietar supraviețuiește delegatului, iar referința rămâne, apelarea metodei delegatului va duce la EXC_BAD_ACCESS. Referința weak rezolvă această problemă automat: după eliberarea delegatului, proprietatea devine nil. Totuși, în scenarii multi-thread, este recomandat să verificați delegatul în firul principal.

Număr excesiv de metode în protocol

Un protocol cu peste 20 de metode încalcă principiul separării interfețelor (ISP). UITableViewDelegate conține aproximativ 30 de metode opționale — aceasta este o excepție istorică. În protocoalele proprii, este mai bine să împărțiți responsabilitatea în mai multe protocoale mici, fiecare cu propriul rol.

Exemple Delegate în API-urile de sistem iOS

API-urile de sistem Apple utilizează activ modelul Delegate. Să analizăm trei exemple cheie din UIKit care apar în fiecare aplicație iOS.

APIProtocolMetode cheie
UITableViewUITableViewDelegatedidSelectRowAt, heightForRowAt, willDisplay
UITextFieldUITextFieldDelegateshouldChangeCharactersIn, didBeginEditing, shouldReturn
URLSessionURLSessionDelegatedidReceiveChallenge, didCompleteWithError, didBecomeInvalidWithError

Fiecare dintre aceste protocoale implementează aspecte diferite ale comportamentului: UITableViewDelegate gestionează aspectul și reacția la atingeri, UITextFieldDelegate controlează introducerea textului, URLSessionDelegate procesează evenimentele de rețea. Aceasta demonstrează flexibilitatea modelului: delegatul poate fi adaptat oricărui domeniu de responsabilitate.

Întrebări frecvente

Care este diferența dintre delegate și dataSource în iOS?

Delegate gestionează comportamentul și aspectul (înălțimea celulei, reacția la atingere). DataSource furnizează date (numărul de rânduri, conținutul celulelor). În UITableViewDelegate și UITableViewDataSource — sunt două protocoale separate, care împart responsabilitatea pentru prezentare și date.

De ce delegate este declarat ca weak?

Referința weak previne retain cycle. Proprietarul (de exemplu, UITableView) menține referința către delegat doar ca weak. Dacă delegatul (UIViewController) deține tabelul, o referință strong către delegat ar crea un ciclu: ViewController → UITableView → Delegate (ViewController). Weak întrerupe acest ciclu.

Se poate folosi delegate în SwiftUI?

În SwiftUI, modelul Delegate este folosit mai rar — este înlocuit de @Binding, @State și closure-uri. Totuși, delegate este încă utilizat pentru integrarea UIKit prin UIViewRepresentable. De exemplu, MKMapViewDelegate și WKUIDelegate rămân relevante la împachetarea componentelor UIKit în SwiftUI.

Ce este @objc optional în protocoalele Swift?

@objc optional permite declararea metodelor opționale într-un protocol Swift. Este un mecanism de compatibilitate cu Objective-C runtime. Fără @objc, toate metodele protocolului Swift sunt implicit obligatorii. Optional este utilizat în protocoalele UIKit, unde delegatul poate implementa doar metodele de care are nevoie.

Câți delegați poate avea un obiect?

Un obiect poate avea doar un delegat pentru fiecare proprietate delegate. Dacă trebuie să notificați mai multe obiecte, utilizați multicast delegate, un array de delegați sau NotificationCenter. Modelul Delegate este conceput inițial ca o relație 1:1.

Rezumat

  • Delegate — model de proiectare comportamentală care transferă executarea unei sarcini de la un obiect la altul printr-un protocol
  • Protocolul Swift declară un set de metode; metodele opționale sunt marcate cu @objc optional, cele obligatorii sunt întotdeauna implementate
  • Referința weak către delegat este obligatorie pentru a preveni retain cycle și scurgerile de memorie
  • UITableViewDelegate — cel mai cunoscut exemplu; metodele sale gestionează înălțimea, selecția și afișarea celulelor
  • Delegate se deosebește de NotificationCenter prin relația 1:1 față de 1:N și siguranța completă a tipurilor
  • Objective-C necesită verificarea respondsToSelector: pentru metodele opționale, Swift gestionează acest lucru automat
  • Recomandare: utilizați delegate pentru callback-uri complexe cu mai multe metode conexe și closure pentru închideri simple

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și