Delegate — je návrhový vzor, při kterém jeden objekt deleguje provádění úkolů jinému objektu prostřednictvím protokolu s předdefinovanými metodami. Ve vývoji iOS je Delegate jedním ze základních vzorů Cocoa Touch, používaným pro asynchronní oznámení bez přímého spojení mezi odesílatelem a příjemcem. Podle Apple Documentation (2025) se delegování aplikuje v Foundation a UIKit pro zpracování událostí tabulek, síťových požadavků a správy polohy. Vzor zajišťuje slabé propojení komponent a opětovné použití kódu.
Hlavní body
Delegate (delegát) — je objekt, který implementuje určitý protokol a přijímá oznámení o událostech jiného objektu. Vzor Delegation je alternativou k dědičnosti: místo vytváření podtřídy pro přepisování metod objekt deleguje zpracování událostí externímu objektu. V iOS je delegation implementován prostřednictvím Swift protokolů s povinnými a volitelnými metodami. Vlastnost delegate je vždy deklarována jako weak var, aby se zabránilo cyklickým referencím mezi objekty.
Protokol delegate definuje kontrakt interakce mezi objekty. Povinné metody musí být implementovány delegátem, jinak se kód nezkompiluje. Volitelné metody jsou označeny atributem @objc optional a umožňují delegátovi reagovat pouze na potřebné události. Názvy metod se řídí konvencí: první parametr — odesílající objekt, druhý — data události. Například tableView(_:didSelectRowAt:) označuje, že odesílatelem je UITableView a data jsou index vybraného řádku.
// Protokol Delegate
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)
}
// Třída používající Delegate
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()
}
}
Vlastnost delegate musí být deklarována jako weak var (slabý ukazatel) pro zabránění retain cycle. Pokud by reference byla silná, delegát a delegující objekt by se vzájemně držely a ARC by nemohla uvolnit jejich paměť. Protokoly delegate dědí AnyObject (pouze pro třídy), což umožňuje použití weak. Struktury a enum nemohou být delegáty kvůli sémantice hodnot. Alternativa pro value types — callback closures.
class ViewController: DownloadManagerDelegate {
let manager = DownloadManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self // weak — žádný retain cycle
manager.startDownload(from: url)
}
func downloadManager(_ manager: DownloadManager, didFinishWith data: Data) {
processData(data)
}
func downloadManager(_ manager: DownloadManager, didFailWith error: Error) {
showError(error)
}
}
Vzor Delegate funguje na principu „jeden-na-jednoho”: jeden odesílající objekt může mít v daném okamžiku pouze jednoho delegáta. Když dojde k události, odesílatel zkontroluje, zda je delegate nastaven, a zavolá odpovídající metodu protokolu. Výhoda oproti přímému volání — odesílatel nezná typ delegáta, pouze to, že odpovídá protokolu. To je v souladu s principem inverze závislostí (DIP) z SOLID.
Delegát je nastaven přiřazením: someObject.delegate = self. Při dealokaci delegáta se vlastnost automaticky stane nil kvůli weak sémantice. Před voláním metody delegate se kontroluje prostřednictvím optional chaining: delegate?.method(). Pokud je delegate nil — volání je ignorováno bez pádu. Pro volitelné metody protokolu se používá dodatečná kontrola: delegate?.responds(to: #selector(...)), i když v Swift je tato kontrola obvykle implicitní prostřednictvím deklarace volitelné metody.
V vícevláknovém prostředí se delegate používá pro asynchronní vrácení výsledku. URLSession poskytuje URLSessionDelegate s metodami volanými při přijetí dat, timeoutu nebo chybě autentizace. Metody delegate se provádějí v backendové frontě URLSession, proto je vyžadována dispatche na main queue pro aktualizace UI. Asynchronní delegate neblokuje volající vlákno, což umožňuje pokračování dalších úkolů.
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 a Callback řeší stejný úkol — asynchronní oznámení — ale různými způsoby. Delegate používá protokol s pojmenovanými metodami, callback — closure se zachycením kontextu. Volba závisí na počtu událostí, složitosti podpisů a architektonických preferencích. Apple doporučuje delegate pro API s více událostmi (UITableView — 20+ metod) a callback pro jednorázová dokončení.
Delegate je preferován, když je třeba zpracovat několik různých událostí z jednoho zdroje. Například CLLocationManager informuje delegáta o změně polohy, chybách oprávnění, vstupu/výstupu z geozón a změně stavu služeb. Každá událost je samostatná metoda protokolu s jasným názvem a typovanými parametry. Delegate je také vhodný pro konfiguraci chování (metody should, will, did).
Callback je jednodušší pro jednorázové požadavky s jedním výsledkem. Completion handler v URLSession.dataTask zabírá jeden řádek v místě volání oproti nejméně třem metodám protokolu. Callback je také přirozenější pro funkční řetězce (map, flatMap, async/await). Při vnoření více než 2-3 úrovní se však callback mění v Callback Hell, zatímco delegate zůstává vždy plochý.
iOS SDK obsahuje desítky vestavěných protokolů delegate pro různé subsystémy. Každý z nich je navržen pro konkrétní scénář interakce. Podle Apple Documentation (2025) jsou nejpoužívanější delegate UITableViewDelegate, UITextFieldDelegate, CLLocationManagerDelegate, URLSessionDelegate a UNUserNotificationCenterDelegate. Tyto protokoly obsahují 3 až 30 metod s různým stupněm povinnosti.
UITableViewDelegate spravuje vzhled a chování buněk tabulky. Obsahuje metody pro zpracování výběru řádků, nastavení výšky buněk, vlastní zobrazení header/footer a swipe akce. Všechny metody protokolu jsou volitelné, což umožňuje implementovat pouze potřebnou funkcionalitu. Při absenci delegáta tabulka pracuje s výchozím nastavením. Historicky se delegate kombinoval s UITableViewDataSource.
URLSessionDelegate poskytuje detailní kontrolu nad HTTP požadavky. Metody delegáta jsou volány při přijetí odpovědi serveru, dat, dokončení stahování. Specializované podprotokoly URLSessionTaskDelegate a URLSessionDataDelegate rozšiřují základní funkcionalitu pro specifické typy úkolů. Delegate je vyžadován pro podporu stahování na pozadí, SSL certifikátů a vlastního zpracování přesměrování.
| Delegate | Metod | Účel |
|---|---|---|
| UITableViewDelegate | 25 | Vzhled a interakce s tabulkou |
| UITextFieldDelegate | 8 | Zpracování vstupu textu a klávesnice |
| CLLocationManagerDelegate | 12 | Aktualizace polohy a geozóny |
| URLSessionDelegate | 6 | Správa HTTP relace a certifikátů |
| UNUserNotificationCenterDelegate | 4 | Zpracování push oznámení na popředí |
Správa paměti je kritickým aspektem práce s delegate v iOS. ARC (Automatic Reference Counting) automaticky spravuje paměť, ale pouze při správném použití weak/unowned referencí. Porušení pravidel vede k únikům paměti nebo předčasné dealokaci. Delegate deklarovaný jako strong vytváří retain cycle, pokud vlastník delegáta také uchovává referenci na delegující objekt.
Retain cycle vzniká, když objekt A (vlastník) nastaví sebe jako delegáta objektu B a B uchovává silnou referenci na delegate. Příklad: ViewController vytvoří URLSession, nastaví self jako delegáta relace, ale URLSession ve výchozím nastavení uchovává silnou referenci na delegate, pokud není zadán delegateQueue. Řešení — vždy kontrolujte dokumentaci API pro typ reference na delegate (weak nebo strong) a explicitně vynulujte delegate v deinit.
class SafeViewController: UIViewController {
private var session: URLSession?
private var service: NetworkService?
override func viewDidLoad() {
super.viewDidLoad()
service = NetworkService()
service?.delegate = self
}
deinit {
// Vynulování delegate v deinit — best practice
service?.delegate = nil
session?.invalidateAndCancel()
}
}
// URLSession s weak delegate přes NSObject
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
)
}
}
Před voláním metody delegáta je třeba zkontrolovat, zda delegát existuje (není nil) a implementuje volanou metodu. Pro povinné metody protokolu není kontrola nutná — kompilátor zaručuje implementaci. Pro volitelné metody použijte respond(to:) nebo optional chaining. Pokud byl delegát dealokován, weak reference se automaticky stane nil a volání delegáta je ignorováno. Toto je bezpečné chování, které nevyžaduje další zpracování.
Vývojáři často dělají chyby při práci s vzorem Delegate, zejména v počátečních fázích učení iOS. Nejčastější: retain cycle kvůli strong delegate, zapomenutí volání delegate?.method(), nesprávný podpis metod protokolu, nastavení delegate po zahájení operace a vícevláknové kolize. Pojďme prozkoumat každou chybu a způsoby její prevence.
Nejkritičtější chyba — deklarování vlastnosti delegate jako strong var místo weak var. To vytváří retain cycle, při kterém ani delegát, ani delegující objekt nemohou být uvolněny. Důsledky: únik paměti, zpomalení aplikace a skryté chyby. Řešení: vždy používejte weak var pro delegate a protokol dědíte z AnyObject, abyste vyloučili použití value types jako delegáta.
Pokud je delegate nastaven po zavolání asynchronní metody, první události mohou být ztraceny. Příklad: volání startDownload() před přiřazením manager.delegate = self vede ke ztrátě callbacku o dokončení, pokud se stahování provádí synchronně nebo velmi rychle. Řešení: nastavte delegate před voláním asynchronní metody a dokumentujte pořadí inicializace v komentářích protokolu.
Často kladené otázky
Weak zabraňuje retain cycle mezi delegátem a delegujícím objektem. Pokud by reference byla silná, objekty by se vzájemně držely a ARC by je nemohla uvolnit. Weak reference se automaticky stane nil při dealokaci delegáta. Toto je standardní praxe Cocoa Touch od dob Objective-C a byla zachována ve Swift pro zpětnou kompatibilitu.
Delegate zpracovává události a řídí chování (výška buněk, reakce na kliknutí). DataSource poskytuje data pro zobrazení (počet řádků, buňky). Delegate odpovídá na otázku “jak?”, dataSource — na otázku “co?”. V iOS jsou oba implementovány prostřednictvím protokolů, často ve stejném kontroleru, ale koncepčně odděleny.
Ne, pokud protokol dědí AnyObject (třídní protokol). Weak reference jsou dostupné pouze pro reference types (třídy). Pro value types (struct, enum) použijte callback closures nebo samostatnou wrapper třídu. Pokud protokol kontrolujete, nemusíte dědit AnyObject, ale pak je weak zakázán — vědomě vybírejte mezi weak-delegátem a struct-delegátem.
responds(to:) — metoda NSObjectProtocol, která kontroluje, zda objekt implementuje zadaný selector. Používá se pro kontrolu volitelných @objc metod protokolu před voláním. Bez této kontroly povede volání neimplementované volitelné metody k NSInvalidArgumentException. Ve Swift pro protokoly s @objc optional může být kontrola implicitní prostřednictvím optional binding.
Ne, delegate je vzor delegování, nikoli singleton. Na rozdíl od singletonu může být delegát nahrazen za běhu a existuje v jedné instanci pro každý delegující objekt. Jeden objekt může být delegátem pro více odesílatelů. Singleton je vytvářecí vzor zaručující jedinou instanci třídy a nemá nic společného s delegováním.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také