Delegate: bu nədir, delegasiya nümunəsi və iOS-da necə işləyir

Müəllif: IT Sectr Dərc olunub: 2026-03-17 Oxuma vaxtı: 10 dəq

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 — obyektin hadisələrin işlənməsini protokol vasitəsilə digər obyektə həvalə etdiyi nümunə.
  • Protocol Swift-də delegate-in tətbiq etməli və ya edə biləcəyi metodlar toplusunu müəyyən edir.
  • Weak reference retain cycle-dən qaçmaq üçün delegate xassəsi üçün məcburidir.
  • @objc optional protokol metodlarını isteğe bağlı etməyə imkan verir.
  • URLSessionDelegate — şəbəkə sorğusu hadisələrinin işlənməsi üçün asinxron delegate.

Delegate nədir?

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 protokolunun təyin edilməsi

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.

swift
// 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-ə zəif istinad

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.

swift
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)
    }
}

iOS-da Delegate nümunəsi necə işləyir?

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ın həyat dövrü

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.

Delegate vasitəsilə asinxron bildiriş

Ç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.

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: yanaşmaların müqayisəsi

DelegateCallback 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 nə vaxt üstündür

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 nə vaxt üstündür

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-da daxili Delegatlar

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

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

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.

DelegateMetodTəyinat
UITableViewDelegate25Cədvəlin görünüşü və qarşılıqlı əlaqə
UITextFieldDelegate8Mətn daxiletmə və klaviatura emalı
CLLocationManagerDelegate12Yer yeniləməsi və geozonalar
URLSessionDelegate6HTTP sessiyası və sertifikatların idarə edilməsi
UNUserNotificationCenterDelegate4Ön planda push bildirişlərinin işlənməsi

Delegate ilə işdə yaddaşın idarə edilmə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.

Delegate vasitəsilə Retain cycle

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.

swift
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
        )
    }
}

Çağırmazdan əvvəl delegate-in təhlükəsiz yoxlanılması

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.

Delegate tətbiqində tipik səhvlə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.

Strong reference weak əvəzinə

Ə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.

Əməliyyat başladıqdan sonra delegate-in qurulması

Ə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

Niyə delegate weak olaraq elan edilir?

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 və dataSource arasında fərq nədir?

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.

Struct delegate kimi istifadə edilə bilərmi?

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:) metodu nədir və nə üçün lazımdır?

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.

Delegate singleton-durmu?

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ə

  • Delegate — obyektin hadisələrin işlənməsini tipli metodları olan protokol vasitəsilə digər obyektə həvalə etdiyi nümunə.
  • Weak var delegate xassəsi üçün retain cycle və yaddaş sızmalarının qarşısını almaq üçün məcburidir.
  • Protokol məcburi və isteğe bağlı (@objc optional) delegasiya metodlarını müəyyən edir.
  • iOS SDK 15+ daxili delegate protokolu ehtiva edir: UITableViewDelegate, URLSessionDelegate, CLLocationManagerDelegate.
  • Delegate bir mənbədən 3+ fərqli hadisə olduqda callback-dən üstündür (CLLocationManager).
  • Asinxron delegate URLSession-da axını bloklamadan məlumat və irəliləyiş əldə etmək üçün istifadə olunur.
  • Delegate-i asinxron əməliyyat başlamazdan əvvəl qurun və təhlükəsiz yaddaş işi üçün deinit-də sıfırlayın.

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.

Layihəni müzakirə et

Həm də oxuyun