Delegate — bir obyektin tapşırığın yerinə yetirilməsini başqa bir obyektə həvalə etdiyi dizayn nümunəsidir. iOS-da nümunə Swift protokolları və @protocol Objective-C vasitəsilə həyata keçirilir. Delegation Cocoa Touch-un əsas nümunələrindən biridir, UITableViewDelegate, UITextFieldDelegate və yüzlərlə digər Apple API-lərində istifadə olunur. Apple Developer Documentation (2025) məlumatına görə, UIKit sistem siniflərinin təxminən 70%-i miras almadan davranışı fərdiləşdirmək üçün delegatlardan istifadə edir.
Əsas məqamlar
Delegate — obyektə öz vəzifələrinin bir hissəsini başqa bir obyektə ötürməyə imkan verən davranış dizayn nümunəsidir. Mirasdan fərqli olaraq, burada uşaq sinif valideynin metodlarını ləğv etmir, delegat kompozisiyadan istifadə edir: sahib-obyekt delegata istinad saxlayır və müəyyən nöqtələrdə onun metodlarını çağırır.
Delegat protokolu — delegatın icra edə biləcəyi metodlar toplusunu müəyyən edir. Metodlar məcburi (required) və opsional (optional) bölünür. Swift-də protokolun opsional metodları @objc optional açar sözü ilə işarələnir.
A obyekti (sahib) delegate xassəsini — B obyektinə (delegat) weak-istinadı saxlayır. Hadisə baş verdikdə, A yoxlayır ki, B protokolun müvafiq metodunu icra edirmi və onu çağırır. Weak-istinad məcburidir: onsuz delegat yaddaşdan azad oluna bilməz, çünki sahib onu güclü istinadla saxlayır.
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)
// asinxron yükləmə
}
}DataLoader sinifi LoaderDelegate protokolunu təyin edir və yükləmə həyat dövrünün əsas nöqtələrində delegat metodlarını çağırır. AnyObject protokolun yalnız siniflər tərəfindən icra oluna biləcəyinə zəmanət verir — bu weak-istinad üçün lazımdır.
Delegatın tətbiqi Swift-də üç addımı əhatə edir: protokolun elan edilməsi, sahibdə weak delegate xassəsinin yaradılması və delegat sinfində protokolun icrası. Validasiya ilə fərdi UITextField nümunəsində nəzərdən keçirək.
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("Validasiya keçmədi: giriş çox qısadır")
}
}LoginViewController ValidatorDelegate protokolunu icra edir və özünü textField-in delegatı təyin edir. Hər mətn dəyişikliyində ValidatedTextField validate(_:) çağırır, validasiya uğursuz olarsa — validatorDidFail(_:). Controller View və validasiya məntiqi arasında vasitəçi rolunu oynayır.
Delegat, bildirişlər və closure arasında seçim alıcıların sayından və komponentlərin bağlılıq dərəcəsindən asılıdır. Hər bir mexanizm obyektlər arasında ünsiyyət problemini həll edir, lakin fərqli trade-off-larla.
| Xarakteristika | Delegate | NotificationCenter | Closure |
|---|---|---|---|
| Əlaqə növü | 1:1 | 1:N | 1:1 |
| Bağlılıq | Zəif (protokol vasitəsilə) | Çox zəif (açar-sətir) | Orta (kontekstin tutulması) |
| Tip təhlükəsizliyi | Tam | Yoxdur (Any?) | Tam |
| Retain cycle riski | Xeyr (weak) | Xeyr | Bəli (self-in tutulması) |
| Nə vaxt tətbiq edilməli | Çox metodu olan mürəkkəb callbacklər | Çoxlarını maraqlandıran hadisələr | 1-2 callbackli sadə closurelar |
Delegate bir alıcıya əlaqəli hadisələr seriyasını ötürmək lazım olduqda optimaldır. NotificationCenter broadcast bildirişləri üçün daha yaxşıdır. Closure — URLSession-də completion handler kimi sadə asinxron əməliyyatlar üçün.
Objective-C delegatları elan etmək üçün @protocol və @optional istifadə edir. Swift-dən fərqli olaraq, protokolun bütün metodları standart olaraq opsionaldır. Əsas fərq — delegata mesaj göndərməzdən əvvəl respondsToSelector: çağırışı, çünki metod icra olunmaya bilər.
@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];
}
// şəklin asinxron yüklənməsi
}
@endObjective-C-də əsas fərq: opsional metodu çağırmazdan əvvəl respondsToSelector: yoxlaması lazımdır. Swift-də protokolun opsional metodları bu yoxlamanı aradan qaldırır — optional chaining (?.) avtomatik olaraq icra olunmama halını idarə edir.
Delegatlardan istifadə səhvləri yaddaş sızmalarına, tətbiqin çökməsinə və gözəçarpmayan buglara səbəb olur. Beş ən geniş yayılmış problemi nəzərdən keçirək.
Retain cycle — ən çox yayılmış səhv. delegate xassəsi strong olaraq elan edilərsə və delegat öz növbəsində sahib-obyektə sahib olarsa, saxlama dövrü yaranır. Hər iki obyekt heç vaxt yaddaşdan azad olunmayacaq. Həll yolu: Swift-də həmişə delegatı weak var, Objective-C-də @property (weak) olaraq elan edin.
Sahib-obyekt delegatı yaşayırsa və istinad qalırsa, delegat metodunun çağırılması EXC_BAD_ACCESS-ə səbəb olur. Weak-istinad bu problemi avtomatik həll edir: delegat azad edildikdən sonra xassə nil olur. Lakin çoxaxışlı ssenarilərdə əlavə olaraq delegatı əsas axında yoxlamaq məsləhətdir.
20+ metodu olan protokol interfeys ayrılması prinsipini (ISP) pozur. UITableViewDelegate təxminən 30 opsional metod ehtiva edir — bu tarixən formalaşmış istisnadır. Öz protokollarınızda məsuliyyəti bir neçə kiçik protokola bölmək daha yaxşıdır, hər biri öz rolu ilə.
Apple-ın sistem API-ləri Delegate nümunəsindən fəal şəkildə istifadə edir. Hər iOS tətbiqində rast gəlinən UIKit-dən üç əsas nümunəyə baxaq.
| API | Protokol | Əsas metodlar |
|---|---|---|
| UITableView | UITableViewDelegate | didSelectRowAt, heightForRowAt, willDisplay |
| UITextField | UITextFieldDelegate | shouldChangeCharactersIn, didBeginEditing, shouldReturn |
| URLSession | URLSessionDelegate | didReceiveChallenge, didCompleteWithError, didBecomeInvalidWithError |
Bu protokolların hər biri davranışın müxtəlif aspektlərini həyata keçirir: UITableViewDelegate görünüş və toxunma reaksiyasını idarə edir, UITextFieldDelegate mətn daxil edilməsini nəzarət edir, URLSessionDelegate şəbəkə hadisələrini emal edir. Bu nümunənin çevikliyini göstərir: delegat istənilən məsuliyyət sahəsinə uyğunlaşdırıla bilər.
Tez-tez verilən suallar
Delegate davranışı və görünüşü idarə edir (hüceyrə hündürlüyü, toxunma reaksiyası). DataSource məlumatları təmin edir (sətirlərin sayı, hüceyrələrin məzmunu). UITableViewDelegate və UITableViewDataSource — təqdimat və məlumat üçün məsuliyyəti bölən iki ayrı protokoldur.
Weak-istinad retain cycle-ın qarşısını alır. Sahib (məsələn, UITableView) delegata yalnız weak olaraq istinad saxlayır. Əgər delegat (UIViewController) cədvələ sahibdirsə, delegata güclü istinad bir dövr yaradardı: ViewController → UITableView → Delegate (ViewController). Weak bu dövrü qırır.
SwiftUI-də Delegate nümunəsi daha az istifadə olunur — onu @Binding, @State və closurelar əvəz edir. Lakin delegate UIViewRepresentable vasitəsilə UIKit inteqrasiyası üçün hələ də tətbiq olunur. Məsələn, MKMapViewDelegate və WKUIDelegate UIKit komponentlərini SwiftUI-ə bükərkən aktual qalır.
@objc optional Swift protokolunda isteğe bağlı metodları elan etməyə imkan verir. Bu Objective-C runtime ilə uyğunluq mexanizmidir. @objc olmadan Swift protokolunun bütün metodları standart olaraq məcburidir. Optional UIKit protokollarında istifadə olunur, burada delegat yalnız lazım olan metodları icra edə bilər.
Bir obyektin hər delegate xassəsi üçün yalnız bir delegatı ola bilər. Bir neçə obyekti xəbərdar etmək lazımdırsa, multicast delegate, delegatlar massivi və ya NotificationCenter istifadə edin. Delegate nümunəsi əslində 1:1 münasibəti kimi dizayn edilmişdir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun