Delegate: mi ez, delegációs minta és hogyan működik iOS-ben

Szerző: IT Sectr Megjelenés: 2026-03-17 Olvasási idő: 10 perc

Delegate — egy tervezési minta, amelyben egy objektum egy másik objektumra delegálja a feladatok végrehajtását egy előre meghatározott metódusokkal rendelkező protokollon keresztül. Az iOS fejlesztésben a Delegate a Cocoa Touch egyik alapvető mintája, amelyet aszinkron értesítésre használnak a küldő és a fogadó közötti közvetlen kapcsolat nélkül. Az Apple Documentation (2025) szerint a delegálást a Foundation-ben és UIKit-ben alkalmazzák táblaesemények, hálózati kérések és helykezelés feldolgozására. A minta laza kapcsolódást biztosít a komponensek között és a kód újrafelhasználását.

Főbb pontok

  • Delegate — minta, amelyben az objektum az események feldolgozását egy másik objektumra bízza egy protokollon keresztül.
  • Protocol a Swift-ben meghatározza a metódusok halmazát, amelyeket a delegate-nek meg kell vagy lehet implementálnia.
  • Weak reference kötelező a delegate tulajdonságnál a retain cycle elkerülése érdekében.
  • @objc optional lehetővé teszi a protokoll metódusainak opcionálissá tételét az implementációban.
  • URLSessionDelegate — aszinkron delegate a hálózati kérés eseményeinek feldolgozásához.

Mi az a Delegate?

Delegate (delegált) — egy objektum, amely implementál egy adott protokollt, és értesítéseket kap egy másik objektum eseményeiről. A Delegation minta alternatívája az öröklésnek: ahelyett, hogy alosztályt hozna létre metódusok felülírásához, az objektum egy külső objektumra delegálja az események feldolgozását. Az iOS-ben a delegation Swift protokollokon keresztül van implementálva kötelező és opcionális metódusokkal. A delegate tulajdonság mindig weak var-ként van deklarálva a ciklikus hivatkozások elkerülése érdekében.

A Delegate protokoll meghatározása

A delegate protokoll meghatározza az objektumok közötti interakciós szerződést. Kötelező metódusokat a delegáltnak implementálnia kell, különben a kód nem fordul le. Opcionális metódusok az @objc optional attribútummal vannak jelölve, és lehetővé teszik a delegált számára, hogy csak a szükséges eseményekre reagáljon. A metódusnevek konvenciót követnek: első paraméter — a küldő objektum, második — az esemény adatai. Például a tableView(_:didSelectRowAt:) azt jelzi, hogy a küldő UITableView, az adat pedig a kiválasztott sor indexe.

swift
// Delegate protokoll
protocol DownloadManagerDelegate: AnyObject {
    func downloadManager(_ manager: DownloadManager,
                          didFinishWith data: Data)
    func downloadManager(_ manager: DownloadManager,
                          didFailWith error: Error)

    @objc optional func downloadManager(_ manager: DownloadManager,
                                didUpdateProgress progress: Float)
}

// Delegate-et használó osztály
class DownloadManager {
    weak var delegate: DownloadManagerDelegate?

    func startDownload(from url: URL) {
        URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
            guard let self else { return }
            if let error = error {
                self.delegate?.downloadManager(self, didFailWith: error)
            } else if let data = data {
                self.delegate?.downloadManager(self, didFinishWith: data)
            }
        }.resume()
    }
}

Gyenge hivatkozás a delegate-re

A delegate tulajdonságot weak var (gyenge mutató) ként kell deklarálni a retain cycle megelőzése érdekében. Ha a hivatkozás erős lenne, a delegált és a delegáló objektum egymást tartaná, és az ARC nem tudná felszabadítani a memóriájukat. A delegate protokollok az AnyObject-ből (csak osztályok számára) örökölnek, ami lehetővé teszi a weak használatát. A struktúrák és enum-ok nem lehetnek delegáltak az értékszemantika miatt. Alternatíva value types számára — callback closure-ok.

swift
class ViewController: DownloadManagerDelegate {
    let manager = DownloadManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        manager.delegate = self // weak — nincs retain cycle
        manager.startDownload(from: url)
    }

    func downloadManager(_ manager: DownloadManager, didFinishWith data: Data) {
        processData(data)
    }

    func downloadManager(_ manager: DownloadManager, didFailWith error: Error) {
        showError(error)
    }
}

Hogyan működik a Delegate minta iOS-ben?

A Delegate minta az „egy-az-egyhez” elv szerint működik: egy küldő objektumnak egyszerre csak egy delegáltja lehet. Amikor egy esemény bekövetkezik, a küldő ellenőrzi, hogy a delegate be van-e állítva, és meghívja a protokoll megfelelő metódusát. Előny a közvetlen hívással szemben — a küldő nem ismeri a delegált típusát, csak azt, hogy megfelel a protokollnak. Ez megfelel a függőséginverzió elvének (DIP) a SOLID-ból.

A delegált életciklusa

A delegált hozzárendeléssel kerül beállításra: someObject.delegate = self. A delegált felszabadításakor a tulajdonság automatikusan nil lesz a weak szemantika miatt. A delegate metódus meghívása előtt optional chaining-en keresztül ellenőrzésre kerül: delegate?.method(). Ha a delegate nil — a hívás figyelmen kívül lesz hagyva crash nélkül. A protokoll opcionális metódusaihoz további ellenőrzés használatos: delegate?.responds(to: #selector(...)), bár a Swift-ben ez az ellenőrzés általában implicit az opcionális metódus deklarációján keresztül.

Aszinkron értesítés Delegate-en keresztül

Többszálas környezetben a delegate az eredmény aszinkron visszaadására szolgál. URLSession URLSessionDelegate-et biztosít metódusokkal, amelyek adatok fogadásakor, időtúllépéskor vagy hitelesítési hibakor hívódnak meg. A delegate metódusok az URLSession háttérvárólistájában hajtódnak végre, ezért a UI frissítésekhez a main queue-ra történő diszpécselés szükséges. Az aszinkron delegate nem blokkolja a hívó szálat, lehetővé téve más feladatok folytatását.

swift
class NetworkService: NSObject, URLSessionDataDelegate {
    private lazy var session = URLSession(
        configuration: .default,
        delegate: self,
        delegateQueue: OperationQueue()
    )
    private var receivedData = Data()

    func urlSession(_ session: URLSession,
                    dataTask: URLSessionDataTask,
                    didReceive data: Data) {
        receivedData.append(data)
        let progress = Float(receivedData.count) / Float(expectedSize)
        DispatchQueue.main.async {
            self.progressHandler?(progress)
        }
    }

    func urlSession(_ session: URLSession,
                    task: URLSessionTask,
                    didCompleteWithError error: Error?) {
        if let error = error {
            delegate?.networkService(self, didFailWith: error)
        } else {
            delegate?.networkService(self, didReceive: receivedData)
        }
    }
}

Delegate vs Callback: megközelítések összehasonlítása

Delegate és Callback ugyanazt a feladatot oldja meg — aszinkron értesítés —, de különböző módon. A Delegate nevesített metódusokkal rendelkező protokollt használ, a callback — kontextusbefogással rendelkező closure-t. A választás az események számától, az aláírások bonyolultságától és az architekturális preferenciáktól függ. Az Apple a delegate-t ajánlja sok eseményű API-khoz (UITableView — 20+ metódus), a callback-t pedig egyszeri befejezésekhez.

Mikor nyer a Delegate

A delegate előnyösebb, amikor több különböző eseményt kell feldolgozni egy forrásból. Például a CLLocationManager értesíti a delegáltat a helyváltozásról, engedélyhibákról, geozónákba való belépésről/kilépésről és a szolgáltatás állapotának változásáról. Minden esemény egy külön protokollmetódus egyértelmű névvel és típusos paraméterekkel. A delegate a viselkedés konfigurálásához is kényelmes (should, will, did metódusok).

Mikor nyer a Callback

A callback egyszerűbb egyszeri kérésekhez egyetlen eredménnyel. Completion handler az URLSession.dataTask-ben egy sort foglal el a hívási ponton, szemben a protokoll legalább három metódusával. A callback természetesebb a funkcionális láncokhoz is (map, flatMap, async/await). 2-3 szintnél mélyebb egymásba ágyazásnál azonban a callback Callback Hellé válik, míg a delegate mindig lapos marad.

Beépített Delegáltak az iOS SDK-ban

Az iOS SDK több tucat beépített delegate protokollt tartalmaz különböző alrendszerek számára. Mindegyik egy adott interakciós forgatókönyvhöz készült. Az Apple Documentation (2025) szerint a leggyakrabban használt delegate-ek a UITableViewDelegate, UITextFieldDelegate, CLLocationManagerDelegate, URLSessionDelegate és UNUserNotificationCenterDelegate. Ezek a protokollok 3 és 30 közötti metódust tartalmaznak különböző kötelező jelleggel.

UITableViewDelegate

UITableViewDelegate kezeli a táblázatcellák megjelenését és viselkedését. Metódusokat tartalmaz sor kiválasztásának feldolgozásához, cellamagasság beállításához, egyéni header/footer nézetekhez és csúsztatási műveletekhez. A protokoll minden metódusa opcionális, ami lehetővé teszi csak a szükséges funkciók implementálását. Delegált hiányában a tábla alapértelmezett beállításokkal működik. Történelmileg a delegate a UITableViewDataSource-szal kombinálódott.

URLSessionDelegate

URLSessionDelegate részletes ellenőrzést biztosít a HTTP-kérések felett. A delegált metódusai a szerver válaszának, adatok fogadásakor, letöltés befejezésekor hívódnak meg. A specializált alprotokollok URLSessionTaskDelegate és URLSessionDataDelegate kiterjesztik az alapfunkcionalitást bizonyos feladattípusokra. A delegate szükséges a háttérletöltések, SSL-tanúsítványok és egyéni átirányítások támogatásához.

DelegateMetódusRendeltetés
UITableViewDelegate25Tábla megjelenése és interakció
UITextFieldDelegate8Szövegbevitel és billentyűzet feldolgozása
CLLocationManagerDelegate12Helyfrissítés és geozónák
URLSessionDelegate6HTTP-munkamenet és tanúsítványok kezelése
UNUserNotificationCenterDelegate4Push értesítések feldolgozása előtérben

Memóriakezelés a Delegate használatakor

A memóriakezelés kritikus szempont a delegate használatakor iOS-ben. ARC (Automatic Reference Counting) automatikusan kezeli a memóriát, de csak a weak/unowned hivatkozások helyes használatával. A szabályok megsértése memóriaszivárgáshoz vagy idő előtti felszabadításhoz vezet. A strong-ként deklarált delegate retain cycle-t hoz létre, ha a delegált tulajdonosa is hivatkozást tart a delegáló objektumra.

Retain cycle Delegate-en keresztül

Retain cycle akkor keletkezik, amikor az A objektum (tulajdonos) saját magát állítja be a B objektum delegáltjának, és B erős hivatkozást tart a delegate-re. Példa: A ViewController létrehoz egy URLSession-t, beállítja a self-et a munkamenet delegáltjának, de az URLSession alapértelmezés szerint erős hivatkozást tart a delegate-re, ha nincs megadva delegateQueue. Megoldás — mindig ellenőrizze az API dokumentációját a delegate-re való hivatkozás típusáért (weak vagy strong), és explicit állítsa nil-ra a delegate-t a deinit-ben.

swift
class SafeViewController: UIViewController {
    private var session: URLSession?
    private var service: NetworkService?

    override func viewDidLoad() {
        super.viewDidLoad()
        service = NetworkService()
        service?.delegate = self
    }

    deinit {
        // Delegate nilra állítása deinit-ben — best practice
        service?.delegate = nil
        session?.invalidateAndCancel()
    }
}

// URLSession weak delegate-dzsel NSObject-en keresztül
class WeakDelegateSession: NSObject {
    private weak var delegate: URLSessionDelegate?

    func createSession() -> URLSession {
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 1
        return URLSession(
            configuration: .default,
            delegate: self,
            delegateQueue: queue
        )
    }
}

A delegate biztonságos ellenőrzése hívás előtt

A delegált metódusának meghívása előtt ellenőrizni kell, hogy a delegált létezik (nem nil) és implementálja a hívott metódust. A protokoll kötelező metódusainál ellenőrzés nem szükséges — a fordító garantálja az implementációt. Opcionális metódusoknál használja a respond(to:) vagy optional chaining függvényt. Ha a delegált felszabadításra került, a weak hivatkozás automatikusan nil lesz, és a delegált hívása figyelmen kívül marad. Ez biztonságos viselkedés, amely nem igényel további feldolgozást.

Tipikus hibák a Delegate implementálásakor

A fejlesztők gyakran követnek el hibákat a Delegate mintával való munkában, különösen az iOS tanulásának kezdeti szakaszában. Leggyakoribbak: retain cycle a strong delegate miatt, elfelejtett delegate?.method() hívás, a protokoll metódusok helytelen aláírása, a delegate beállítása a művelet megkezdése után, és több szálas ütközések. Vizsgáljuk meg az egyes hibákat és megelőzésük módjait.

Strong reference weak helyett

A legkritikusabb hiba — a delegate tulajdonság deklarálása strong var-ként weak var helyett. Ez egy olyan retain cycle-t hoz létre, amelyben sem a delegált, sem a delegáló objektum nem szabadítható fel. Következmények: memóriaszivárgás, az alkalmazás lelassulása és rejtett hibák. Megoldás: mindig weak var-t használjon a delegate-hez, és a protokollt az AnyObject-ből származtassa, hogy kizárja a value types használatát delegáltként.

A delegate beállítása a művelet megkezdése után

Ha a delegate egy aszinkron metódus meghívása után kerül beállításra, az első események elveszhetnek. Példa: a startDownload() meghívása a manager.delegate = self hozzárendelés előtt a befejezési callback elvesztéséhez vezet, ha a letöltés szinkron vagy nagyon gyors. Megoldás: állítsa be a delegate-t az aszinkron metódus meghívása előtt, és dokumentálja az inicializálási sorrendet a protokoll megjegyzéseiben.

Gyakran ismételt kérdések

Miért weak-ként van deklarálva a delegate?

A Weak megakadályozza a retain cycle-t a delegált és a delegáló objektum között. Ha a hivatkozás erős lenne, az objektumok egymást tartanák, és az ARC nem tudná felszabadítani őket. A weak-hivatkozás automatikusan nil lesz a delegált felszabadításakor. Ez a Cocoa Touch szokásos gyakorlata az Objective-C megjelenése óta, és a Swift-ben is megmaradt a visszafelé kompatibilitás érdekében.

Mi a különbség a delegate és a dataSource között?

Delegate feldolgozza az eseményeket és kezeli a viselkedést (cellamagasság, kattintásra adott reakció). DataSource adatokat szolgáltat a megjelenítéshez (sorok száma, cellák). A delegate a “hogyan?” kérdésre válaszol, a dataSource a “mit?” kérdésre. Az iOS-ben mindkettő protokollokon keresztül van implementálva, gyakran ugyanabban a vezérlőben, de fogalmilag elkülönül.

Használható-e a struct delegate-ként?

Nem, ha a protokoll az AnyObject-ből (osztályprotokoll) származik. A weak-hivatkozások csak reference types (osztályok) számára elérhetők. A value types (struct, enum) esetében használjon callback closure-okat vagy egy külön wrapper osztályt. Ha Ön irányítja a protokollt, nem származtathatja AnyObject-ből, de akkor a weak tiltott — válasszon tudatosan a weak-delegate és a struct-delegált között.

Mi az a responds(to:) metódus és mire való?

responds(to:) — az NSObjectProtocol metódusa, amely ellenőrzi, hogy az objektum implementálja-e a megadott selectort. A protokoll opcionális @objc metódusainak ellenőrzésére szolgál hívás előtt. Ezen ellenőrzés nélkül egy nem implementált opcionális metódus meghívása NSInvalidArgumentException-t eredményez. A Swift-ben az @objc optional protokollok esetén az ellenőrzés implicit lehet optional binding-en keresztül.

A Delegate singleton?

Nem, a delegate egy delegációs minta, nem singleton. Ellentétben a singleton-nal, a delegált futásidőben lecserélhető, és minden delegáló objektumhoz egy példányban létezik. Egy objektum több küldő számára is lehet delegált. A singleton egy létrehozási minta, amely egy osztály egyetlen példányát garantálja, és semmi köze a delegáláshoz.

Összefoglalás

  • Delegate — minta, amelyben az objektum az események feldolgozását egy másik objektumra delegálja egy típusos metódusokkal rendelkező protokollon keresztül.
  • Weak var kötelező a delegate tulajdonságnál a retain cycle és memóriaszivárgás megelőzése érdekében.
  • Protokoll meghatározza a kötelező és opcionális (@objc optional) delegációs metódusokat.
  • iOS SDK 15+ beépített delegate protokollt tartalmaz: UITableViewDelegate, URLSessionDelegate, CLLocationManagerDelegate.
  • Delegate előnyösebb a callback-kel szemben 3+ különböző esemény esetén egy forrásból (CLLocationManager).
  • Aszinkron delegate az URLSession-ben szolgál adatok és előrehaladás lekérésére a szál blokkolása nélkül.
  • Állítsa be a delegate-t az aszinkron művelet megkezdése előtt, és állítsa nil-ra a deinit-ben a biztonságos memóriakezeléshez.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is