Delegate — je návrhový vzor, při kterém jeden objekt deleguje provedení úkolu jinému objektu. V iOS je vzor implementován pomocí Swift protokolů a @protocol Objective-C. Delegation je jedním ze základních vzorů Cocoa Touch, používaným v UITableViewDelegate, UITextFieldDelegate a stovkách dalších Apple API. Podle Apple Developer Documentation (2025) přibližně 70% systémových tříd UIKit používá delegáty k přizpůsobení chování bez dědičnosti.
Hlavní body
Delegate — je návrhový vzor chování, který umožňuje objektu přenést část svých povinností na jiný objekt. Na rozdíl od dědičnosti, kde podtřída přepisuje metody rodiče, delegát používá kompozici: vlastnický objekt ukládá referenci na delegáta a volá jeho metody v určitých bodech.
Delegát definuje protokol — sadu metod, které delegát může implementovat. Metody se dělí na povinné (required) a volitelné (optional). Ve Swift jsou volitelné metody protokolu označeny klíčovým slovem @objc optional.
Objekt A (vlastník) obsahuje vlastnost delegate — weak referenci na objekt B (delegát). Když dojde k události, A zkontroluje, zda B implementuje odpovídající metodu protokolu, a zavolá ji. Weak reference je povinná: bez ní delegát nemůže být uvolněn z paměti, protože vlastník ho drží silnou referencí.
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)
// asynchronní načítání
}
}Třída DataLoader definuje protokol LoaderDelegate a volá metody delegáta v klíčových bodech životního cyklu načítání. AnyObject zaručuje, že protokol může být implementován pouze třídami — to je nezbytné pro weak referenci.
Implementace delegáta ve Swift zahrnuje tři kroky: deklarování protokolu, vytvoření weak vlastnosti delegate u vlastníka a implementaci protokolu v třídě-delegátovi. Podívejme se na příklad vlastního UITextField s validací.
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("Validace selhala: vstup je příliš krátký")
}
}LoginViewController implementuje protokol ValidatorDelegate a nastaví se jako delegát textField. Při každé změně textu ValidatedTextField zavolá validate(_:), a pokud validace selže — validatorDidFail(_:). Controller funguje jako prostředník mezi View a logikou validace.
Volba mezi delegátem, oznámeními a closures závisí na počtu příjemců a míře provázanosti komponent. Každý mechanismus řeší problém komunikace mezi objekty, ale s různými kompromisy.
| Charakteristika | Delegate | NotificationCenter | Closure |
|---|---|---|---|
| Typ připojení | 1:1 | 1:N | 1:1 |
| Provázanost | Slabá (přes protokol) | Velmi slabá (řetězcový klíč) | Střední (zachycení kontextu) |
| Typová bezpečnost | Plná | Chybí (Any?) | Plná |
| Riziko retain cycle | Ne (weak) | Ne | Ano (zachycení self) |
| Kdy použít | Složitá callbacky s více metodami | Události zajímající mnoho | Jednoduchá closures s 1-2 callbacky |
Delegate je optimální, když je třeba předat sérii souvisejících událostí jednomu příjemci. NotificationCenter je lepší pro broadcastová oznámení. Closure — pro jednoduché asynchronní operace, jako je completion handler v URLSession.
Objective-C používá @protocol a @optional pro deklarování delegátů. Na rozdíl od Swift jsou všechny metody protokolu standardně volitelné. Klíčový rozdíl — volání respondsToSelector: před odesláním zprávy delegátovi, protože metoda nemusí být implementována.
@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];
}
// asynchronní načítání obrázku
}
@endKlíčový rozdíl v Objective-C: před voláním volitelné metody je nutná kontrola respondsToSelector:. Ve Swift volitelné metody protokolu tuto kontrolu eliminují — optional chaining (?.) automaticky zpracovává případ chybějící implementace.
Chyby při používání delegátů vedou k únikům paměti, pádům aplikace a ne zřejmým bugům. Podívejme se na pět nejčastějších problémů.
Retain cycle — nejčastější chyba. Pokud je vlastnost delegate deklarována jako strong a delegát zároveň vlastní vlastnický objekt, vznikne cyklus držení. Oba objekty nebudou nikdy uvolněny z paměti. Řešení: vždy deklarujte delegáta jako weak var ve Swift nebo @property (weak) v Objective-C.
Pokud vlastnický objekt přežije delegáta a reference zůstane, volání metody delegáta povede k EXC_BAD_ACCESS. Weak reference řeší tento problém automaticky: po uvolnění delegáta se vlastnost stane nil. Ve vícevláknových scénářích se však vyplatí dodatečně kontrolovat delegáta v hlavním vlákně.
Protokol s více než 20 metodami porušuje princip rozdělení rozhraní (ISP). UITableViewDelegate obsahuje asi 30 volitelných metod — to je historická výjimka. Ve vlastních protokolech je lepší rozdělit odpovědnost na několik malých protokolů, každý s vlastní rolí.
Systémová Apple API aktivně používají vzor Delegate. Podívejme se na tři klíčové příklady z UIKit, které se vyskytují v každé iOS aplikaci.
| API | Protokol | Klíčové metody |
|---|---|---|
| UITableView | UITableViewDelegate | didSelectRowAt, heightForRowAt, willDisplay |
| UITextField | UITextFieldDelegate | shouldChangeCharactersIn, didBeginEditing, shouldReturn |
| URLSession | URLSessionDelegate | didReceiveChallenge, didCompleteWithError, didBecomeInvalidWithError |
Každý z těchto protokolů implementuje různé aspekty chování: UITableViewDelegate spravuje vzhled a reakci na dotyk, UITextFieldDelegate kontroluje vstup textu, URLSessionDelegate zpracovává síťové události. To demonstruje flexibilitu vzoru: delegát může být přizpůsoben jakékoli oblasti odpovědnosti.
Často kladené otázky
Delegate spravuje chování a vzhled (výška buňky, reakce na dotyk). DataSource poskytuje data (počet řádků, obsah buněk). UITableViewDelegate a UITableViewDataSource — to jsou dva samostatné protokoly, které rozdělují odpovědnost za prezentaci a data.
Weak reference zabraňuje retain cycle. Vlastník (např. UITableView) drží referenci na delegáta pouze jako weak. Pokud delegát (UIViewController) vlastní tabulku, silná reference na delegáta by vytvořila cyklus: ViewController → UITableView → Delegate (ViewController). Weak tento cyklus přerušuje.
Ve SwiftUI se vzor Delegate používá méně často — nahrazují ho @Binding, @State a closures. Nicméně delegate se stále používá pro integraci UIKit přes UIViewRepresentable. Například MKMapViewDelegate a WKUIDelegate zůstávají relevantní při balení UIKit komponent do SwiftUI.
@objc optional umožňuje deklarovat volitelné metody v Swift protokolu. Jedná se o mechanismus kompatibility s Objective-C runtime. Bez @objc jsou všechny metody Swift protokolu standardně povinné. Optional se používá v UIKit protokolech, kde delegát může implementovat pouze metody, které potřebuje.
Jeden objekt může mít pouze jednoho delegáta pro každou vlastnost delegate. Pokud je třeba informovat více objektů, použijte multicast delegate, pole delegátů nebo NotificationCenter. Vzor Delegate je původně navržen jako vztah 1:1.
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é