Delegate — bu, bir obyektin tapşırıqların icrasını protokol vasitəsilə əvvəlcədən müəyyən edilmiş metodları olan digər obyektə həvalə etdiyi dizayn nümunəsidir. iOS inkişafında Delegate Cocoa Touch-un əsas nümunələrindən biridir və göndərən ilə qəbul edən arasında birbaşa əlaqə olmadan asinxron bildiriş üçün istifadə olunur. Apple Documentation (2025) məlumatına görə, delegasiya Foundation və UIKit-də cədvəl hadisələrinin, şəbəkə sorğularının və yer idarəetməsinin işlənməsi üçün tətbiq olunur. Bu nümunə komponentlərin zəif bağlanmasını və kodun təkrar istifadəsini təmin edir.
Əsas məqamlar
Delegate (delegat) — müəyyən protokolu tətbiq edən və digər obyektin hadisələri haqqında bildirişlər alan obyektdir. Delegation nümunəsi miras almaya alternativdir: metodları ləğv etmək üçün alt sinif yaratmaq əvəzinə, obyekt hadisələrin işlənməsini xarici obyektə həvalə edir. iOS-da delegation məcburi və isteğe bağlı metodları olan Swift protokolları vasitəsilə tətbiq olunur. delegate xassəsi həmişə weak var olaraq elan edilir ki, obyektlər arasında dövri istinadların qarşısı alınsın.
Delegate protokolu obyektlər arasında qarşılıqlı əlaqə kontraktını müəyyən edir. Məcburi metodlar delegat tərəfindən tətbiq edilməlidir, əks halda kod kompilyasiya olunmayacaq. İsteğe bağlı metodlar @objc optional atributu ilə işarələnir və delegata yalnız lazımi hadisələrə reaksiya verməyə imkan verir. Metod adları konvensiyaya uyğundur: birinci parametr — göndərən obyekt, ikinci — hadisə məlumatları. Məsələn, tableView(_:didSelectRowAt:) göstərir ki, göndərən UITableView, məlumat isə seçilmiş sətrin indeksidir.
// Delegate Protokolu
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 istifadə edən sinif
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()
}
}
delegate xassəsi mütləq weak var (zəif göstərici) olaraq elan edilməlidir ki, retain cycle-in qarşısı alınsın. Əgər istinad güclü olsaydı, delegat və delegasiya edən obyekt bir-birini saxlayar və ARC onların yaddaşını boşalda bilməzdi. Delegate protokolları AnyObject-dən (yalnız siniflər üçün) miras alır ki, bu da weak istifadəsinə imkan verir. Strukturlar və enum dəyər semantikası səbəbindən delegat ola bilməz. Value types üçün alternativ — callback closure-lardır.
class ViewController: DownloadManagerDelegate {
let manager = DownloadManager()
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self // weak — retain cycle yoxdur
manager.startDownload(from: url)
}
func downloadManager(_ manager: DownloadManager, didFinishWith data: Data) {
processData(data)
}
func downloadManager(_ manager: DownloadManager, didFailWith error: Error) {
showError(error)
}
}
Delegate nümunəsi „bir-birə" prinsipi ilə işləyir: bir göndərən obyektin müəyyən bir zamanda yalnız bir delegatı ola bilər. Hadisə baş verdikdə, göndərən delegate-in qurulub-qurulmadığını yoxlayır və protokolun müvafiq metodunu çağırır. Üstünlük birbaşa çağırışdan fərqli olaraq — göndərən delegatın tipini bilmir, yalnız onun protokola uyğun olduğunu bilir. Bu, SOLID-dən asılılıqların tərsinə çevrilməsi prinsipinə (DIP) uyğundur.
Delegat təyin etmə yolu ilə qurulur: someObject.delegate = self. Delegatın dealokasiyası zamanı xassə weak semantikası səbəbindən avtomatik olaraq nil olur. delegate metodunu çağırmazdan əvvəl optional chaining vasitəsilə yoxlanılır: delegate?.method(). Əgər delegate nil-dirsə — çağırış crash olmadan nəzərə alınmır. Protokolun isteğe bağlı metodları üçün əlavə yoxlama istifadə olunur: delegate?.responds(to: #selector(...)), baxmayaraq ki, Swift-də bu yoxlama adətən optional method elanı vasitəsilə gizli şəkildə aparılır.
Çoxaxınlı mühitdə delegate nəticənin asinxron qaytarılması üçün istifadə olunur. URLSession məlumat alındıqda, vaxt aşımında və ya autentifikasiya xətasında çağırılan metodları olan URLSessionDelegate təqdim edir. Delegate metodları URLSession fon növbəsində icra olunur, buna görə UI yeniləmələri üçün main queue-ya dispetçerizasiya tələb olunur. Asinxron delegate çağıran axını bloklamır, digər tapşırıqların davam etdirilməsinə imkan verir.
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 və Callback eyni vəzifəni — asinxron bildirişi — həll edir, lakin fərqli üsullarla. Delegate adlandırılmış metodları olan protokoldan, callback isə kontekst tutan closure-dan istifadə edir. Seçim hadisələrin sayından, imzaların mürəkkəbliyindən və memarlıq üstünlüklərindən asılıdır. Apple çoxsaylı hadisələri olan API-lər üçün delegate (UITableView — 20+ metod), birdəfəlik tamamlamalar üçün isə callback tövsiyə edir.
Delegate bir mənbədən bir neçə fərqli hadisəni idarə etmək lazım olduqda üstünlük təşkil edir. Məsələn, CLLocationManager delegata yer dəyişikliyi, icazə xətaları, geozonalara daxilolma/çıxma və xidmət statusunun dəyişməsi barədə bildiriş verir. Hər bir hadisə aydın adı və tipli parametrləri olan ayrıca protokol metodudur. Delegate həmçinin davranış konfiqurasiyası üçün rahatdır (should, will, did metodları).
Callback bir nəticəli birdəfəlik sorğular üçün daha sadədir. Completion handler URLSession.dataTask-də çağırış nöqtəsində bir sətir tutur, protokolun ən azı üç metodu ilə müqayisədə. Callback həmçinin funksional zəncirlər üçün daha təbiidir (map, flatMap, async/await). Lakin 2-3 səviyyədən çox iç-içə olduqda callback Callback Hell-ə çevrilir, delegate isə həmişə düz qalır.
iOS SDK müxtəlif alt sistemlər üçün onlarla daxili delegate protokolu ehtiva edir. Onların hər biri müəyyən bir qarşılıqlı əlaqə ssenarisi üçün nəzərdə tutulub. Apple Documentation (2025) məlumatına görə, ən çox istifadə olunan delegate-lər UITableViewDelegate, UITextFieldDelegate, CLLocationManagerDelegate, URLSessionDelegate və UNUserNotificationCenterDelegate-dir. Bu protokollar müxtəlif məcburilik dərəcəsi olan 3-dən 30-a qədər metod ehtiva edir.
UITableViewDelegate cədvəl xanalarının görünüşünü və davranışını idarə edir. Sətir seçimi, xana hündürlüyünün tənzimlənməsi, fərdi header/footer görünüşləri və sürüşdürmə hərəkətləri üçün metodlar ehtiva edir. Protokolun bütün metodları isteğe bağlıdır, bu da yalnız lazımi funksionallığı tətbiq etməyə imkan verir. Delegat olmadıqda cədvəl standart parametrlərlə işləyir. Tarixən delegate UITableViewDataSource ilə birləşirdi.
URLSessionDelegate HTTP sorğuları üzərində detallı nəzarəti təmin edir. Delegat metodları server cavabı, məlumatlar alındıqda, yükləmə tamamlandıqda çağırılır. İxtisaslaşdırılmış alt protokollar URLSessionTaskDelegate və URLSessionDataDelegate müəyyən tapşırıq növləri üçün əsas funksionallığı genişləndirir. Delegate fon yükləmələri, SSL sertifikatları və fərdi yönləndirmə emalı üçün tələb olunur.
| Delegate | Metod | Təyinat |
|---|---|---|
| UITableViewDelegate | 25 | Cədvəlin görünüşü və qarşılıqlı əlaqə |
| UITextFieldDelegate | 8 | Mətn daxiletmə və klaviatura emalı |
| CLLocationManagerDelegate | 12 | Yer yeniləməsi və geozonalar |
| URLSessionDelegate | 6 | HTTP sessiyası və sertifikatların idarə edilməsi |
| UNUserNotificationCenterDelegate | 4 | Ön planda push bildirişlərinin işlənməsi |
Yaddaşın idarə edilməsi iOS-da delegate ilə işin kritik aspektidir. ARC (Automatic Reference Counting) yaddaşı avtomatik idarə edir, lakin yalnız weak/unowned istinadlarının düzgün istifadəsi ilə. Qaydaların pozulması yaddaş sızmalarına və ya vaxtından əvvəl dealokasiyaya səbəb olur. Strong olaraq elan edilmiş delegate, əgər delegatın sahibi delegasiya edən obyektə istinad saxlayırsa, retain cycle yaradır.
Retain cycle o zaman yaranır ki, A obyekti (sahib) özünü B obyektinin delegatı təyin edir, B isə delegate-ə güclü istinad saxlayır. Nümunə: ViewController URLSession yaradır, self-i sessiyanın delegatı təyin edir, lakin URLSession standart olaraq delegate-ə güclü istinad saxlayır, əgər delegateQueue göstərilməyibsə. Həll — həmişə API sənədlərində delegate-ə istinad növünü (weak və ya strong) yoxlayın və deinit-də delegate-i açıq şəkildə sıfırlayın.
class SafeViewController: UIViewController {
private var session: URLSession?
private var service: NetworkService?
override func viewDidLoad() {
super.viewDidLoad()
service = NetworkService()
service?.delegate = self
}
deinit {
// deinit-də delegate-in sıfırlanması — best practice
service?.delegate = nil
session?.invalidateAndCancel()
}
}
// NSObject vasitəsilə weak delegate ilə URLSession
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
)
}
}
Delegat metodunu çağırmazdan əvvəl delegatın mövcud olduğunu (nil deyil) və çağırılan metodu tətbiq etdiyini yoxlamaq lazımdır. Protokolun məcburi metodları üçün yoxlama tələb olunmur — kompilator tətbiqi təmin edir. İsteğe bağlı metodlar üçün respond(to:) və ya optional chaining istifadə edin. Əgər delegat dealokasiya olunubsa, weak istinad avtomatik olaraq nil olur və delegat çağırışı nəzərə alınmır. Bu, əlavə emal tələb etməyən təhlükəsiz davranışdır.
Proqramçılar, xüsusən iOS-u yenicə mənimsəyərkən, Delegate nümunəsi ilə işdə tez-tez səhv edirlər. Ən geniş yayılmış: strong delegate səbəbindən retain cycle, delegate?.method() çağırmağı unutma, protokol metodlarının səhv imzası, əməliyyat başladıqdan sonra delegate-in qurulması və çoxaxınlı toqquşmalar. Hər bir səhvi və onun qarşısının alınması yollarını nəzərdən keçirək.
Ən kritik səhv — delegate xassəsinin weak var əvəzinə strong var olaraq elan edilməsidir. Bu, nə delegatın, nə də delegasiya edən obyektin boşaldıla bilmədiyi retain cycle yaradır. Nəticələr: yaddaş sızması, tətbiqin yavaşlaması və gizli səhvlər. Həll: həmişə delegate üçün weak var istifadə edin, protokolu isə AnyObject-dən miras alın ki, value types-ın delegat kimi istifadəsi istisna edilsin.
Əgər delegate asinxron metod çağırıldıqdan sonra qurulursa, ilk hadisələr itirilə bilər. Nümunə: manager.delegate = self təyin edilməzdən əvvəl startDownload() çağırmaq, yükləmə sinxron və ya çox sürətli olarsa, tamamlama haqqında callback-in itirilməsinə səbəb olur. Həll: asinxron metodu çağırmazdan əvvəl delegate-i qurun və protokol şərhlərində inisializasiya qaydasını sənədləşdirin.
Tez-tez verilən suallar
Weak delegat və delegasiya edən obyekt arasında retain cycle-in qarşısını alır. Əgər istinad strong olsaydı, obyektlər bir-birini saxlayar və ARC onları boşalda bilməzdi. Weak-istinad delegatın dealokasiyası zamanı avtomatik olaraq nil olur. Bu, Objective-C dövründən Cocoa Touch-un standart təcrübəsidir və geriyə uyğunluq üçün Swift-də saxlanılıb.
Delegate hadisələri emal edir və davranışı idarə edir (xana hündürlüyü, kliklərə reaksiya). DataSource göstərilmək üçün məlumat təqdim edir (sətir sayı, xanalar). Delegate „necə?" sualına, dataSource „nə?" sualına cavab verir. iOS-da hər ikisi protokollar vasitəsilə tətbiq olunur, çox vaxt eyni kontrollerdə, lakin konseptual olaraq ayrılmışdır.
Xeyr, əgər protokol AnyObject-dən (sinif protokolu) miras alırsa. Weak-istinadlar yalnız reference types (siniflər) üçün mövcuddur. Value types (struct, enum) üçün callback closure-larından və ya ayrıca sarıcı sinifdən istifadə edin. Protokola nəzarət edirsinizsə, AnyObject-dən miras almaya bilərsiniz, lakin o zaman weak qadağandır — weak-delegat və struct-delegat arasında şüurlu seçim edin.
responds(to:) — NSObjectProtocol metodu, obyektin göstərilən selektoru tətbiq edib-etmədiyini yoxlayır. Çağırmazdan əvvəl protokolun @objc isteğe bağlı metodlarını yoxlamaq üçün istifadə olunur. Bu yoxlama olmadan tətbiq edilməmiş isteğe bağlı metodun çağırılması NSInvalidArgumentException-a səbəb olur. Swift-də @objc optional olan protokollar üçün yoxlama optional binding vasitəsilə gizli ola bilər.
Xeyr, delegate delegasiya nümunəsidir, singleton deyil. Singleton-dan fərqli olaraq, delegat runtime-da dəyişdirilə bilər və hər bir delegasiya edən obyekt üçün tək nüsxədə mövcuddur. Bir obyekt bir neçə göndərən üçün delegat ola bilər. Singleton sinfin yeganə nüsxəsini təmin edən yaradıcı nümunədir və bunun delegasiya ilə əlaqəsi yoxdur.
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