NotificationCenter — bu, göndərən və qəbul edən arasında birbaşa əlaqə olmadan tətbiq komponentləri arasında bildirişlərin göndərilməsi və qəbulu üçün iOS sistem mexanizmidir. Observer nümunəsinə əsaslanan NotificationCenter, obyektlərə hadisələrə abunə olmağa və onlara asinxron reaksiya verməyə imkan verir. Apple Documentation (2025)-ə görə, NSNotificationCenter həm post(name:object:) vasitəsilə sinxron bildiriş göndərməni, həm də NotificationQueue vasitəsilə təxirə salınmış bildirişləri dəstəkləyir. Bildiriş mərkəzi bir proses çərçivəsində işləyir və tətbiq sərhədlərini keçmir.
Əsas məqamlar
NotificationCenter (NSNotificationCenter) — bu, obyektlər arasında zəif bağlı kommunikasiyanı həyata keçirmək üçün iOS-un daxili mexanizmidir. Observer nümunəsi bir obyektə (göndərən) birbaşa istinad olmadan bir çox digər obyektləri (müşahidəçiləri) hadisənin baş verməsi barədə xəbərdar etməyə imkan verir. NotificationCenter üç varlıqla işləyir: Notification.Name (bildiriş identifikatoru), Notification (məlumat konteyneri) və NotificationCenter (dispetçer). Hər bir tətbiqin ümumi default center-i var.
Notification.Name — bildiriş növünü identifikasiya edən strukturdur. extension Name: Notification.Name("MyNotification") vasitəsilə yaradılır. Notification — name, object (göndərən) və userInfo (məlumat lüğəti) olan obyektdir. Sistem bildirişləri sabitlər kimi elan edilir: UIApplication.didBecomeActiveNotification, UIResponder.keyboardWillShowNotification. Xüsusi bildirişlər ad toqquşmalarının qarşısını almaq üçün extension vasitəsilə qruplaşdırılmalıdır. Adlar tərs-domen olmalıdır.
// Xüsusi bildirişlərin təyin edilməsi
extension Notification.Name {
static let dataDidUpdate =
Notification.Name("com.app.dataDidUpdate")
static let userLoggedOut =
Notification.Name("com.app.userLoggedOut")
}
// Məlumatlarla bildiriş göndərilməsi
let userInfo: [String: Any] = [
"userId": 123,
"timestamp": Date()
]
NotificationCenter.default.post(
name: .dataDidUpdate,
object: nil,
userInfo: userInfo
)
Müşahidəçi addObserver(_:selector:name:object:) metodu ilə bildirişə abunə olur. Selektor — bildiriş alındıqda çağırılacaq metoddur. object parametri müəyyən bir göndərəndən bildirişləri süzməyə imkan verir. object nil olarsa, müşahidəçi göstərilən adla bütün bildirişləri istənilən göndərəndən alır. iOS 9-dan etibarən, block-based API üçün addObserver əl ilə silmə tələb etmir, lakin selector-based hələ də removeObserver tələb edir.
// Bildirişə abunə (selector-based)
NotificationCenter.default.addObserver(
self,
selector: #selector(handleDataUpdate),
name: .dataDidUpdate,
object: nil
)
@objc func handleDataUpdate(_ notification: Notification) {
guard let userId = notification.userInfo?["userId"] as? Int else { return }
updateUI(for: userId)
}
// Bildirişə abunə (block-based, iOS 9+)
var observer: NSObjectProtocol?
observer = NotificationCenter.default.addObserver(
forName: .dataDidUpdate,
object: nil,
queue: .main
) { [weak self] notification in
guard let self else { return }
self.handleNotification(notification)
}
NotificationCenter xəritələmə cədvəlini saxlayır (name → müşahidəçilər dəsti). Göndərən post(name:object:) çağırdıqda, bildiriş mərkəzi bu ada abunə olan bütün müşahidəçiləri sinxron olaraq gəzir və onların selektorlarını və ya bloklarını çağırır. Əsas xüsusiyyət: post bütün handler-lər tamamlanana qədər cari iplik bloklayır. Handler-lər ağır əməliyyatlar yerinə yetirirsə, bu göndərəni ləngidir. NotificationQueue bildirişlərin çatdırılmasını təxirə salmaqla bu problemi həll edir.
post(name:object:userInfo:) metodu bildirişi dərhal bütün müşahidəçilərə göndərir. Çağırış sinxrondur — post-dan sonrakı kod yalnız bütün handler-lər tamamlandıqdan sonra icra olunur. Müşahidəçilərin çağırış sırası təminat verilmir və işə salmalar arasında dəyişə bilər. Ardıcıl emal üçün coalescing ilə NotificationQueue istifadə edin. Eyni bildirişin handler-i içərisində post çağırmayın — bu sonsuz rekursiyaya səbəb olur.
NotificationQueue asinxron çatdırılma üçün bildirişləri növbəyə əlavə edir. Coalescing (eyni bildirişlərin birləşdirilməsi) və çatdırılma növbəsi seçimini (asap, idle, modal) dəstəkləyir. Coalescing tez-tez baş verən hadisələr (yüklənmə vəziyyəti) üçün faydalıdır, yalnız son dəyərlə xəbərdar etmək lazım olduqda. NotificationQueue işə düşmək üçün run loop-dan istifadə edir, buna görə də yalnız aktiv run loop olan ipliklərdə işləyir.
// NotificationQueue vasitəsilə təxirə salınmış göndərmə
let notification = Notification(
name: .dataDidUpdate,
object: self,
userInfo: ["progress": 0.5]
)
// Coalescing: bir neçə bildiriş birinə birləşdirilir
NotificationQueue.default.enqueue(
notification,
postingStyle: .whenIdle,
coalesceMask: .onName,
forModes: [.common]
)
// DispatchQueue vasitəsilə asinxron göndərmə
DispatchQueue.main.async {
NotificationCenter.default.post(name: .dataDidUpdate, object: nil)
}
iOS obyektlər arasında ünsiyyət üçün üç əsas mexanizm təqdim edir: NotificationCenter, Delegate və KVO (Key-Value Observing). Hər biri bildiriş problemini həll edir, lakin bağlılıq, performans və tip təhlükəsizliyi baxımından fərqli kompromislərlə. Mexanizmin seçimi «bir-birə» və ya «birdən-çoxa» münasibətindən və məlumat ötürmə ehtiyacından asılıdır.
| Xüsusiyyət | NotificationCenter | Delegate | KVO |
|---|---|---|---|
| Bağlılıq | Zəif (bildiriş adı) | Güclü (protokol) | Orta (açar) |
| Münasibət | Birdən-çoxa | Bir-birə | Birdən-çoxa |
| Tip təhlükəsizliyi | Aşağı (userInfo Dictionary kimi) | Yüksək (protokol metodları) | Orta (Any?) |
| Performans | Orta (cədvəl gəzintisi) | Yüksək (birbaşa çağırış) | Aşağı (NSObject) |
| Asinxronluq | Sinxron (post bloklayır) | Göndərənin ipliyində sinxron | Dəyişiklik zamanı sinxron |
NotificationCenter bir neçə müstəqil komponentin reaksiya verməli olduğu hadisələr üçün idealdır. Nümunələr: tətbiq parametrlərinin dəyişməsi, istifadəçinin hesabdan çıxması, fonda push bildirişinin alınması. NotificationCenter həmçinin zəif bağlı modullar üçün uyğundur (xüsusiyyət A xüsusiyyət B haqqında bilməməlidir). Çatışmazlıq — tip təhlükəsizliyinin olmaması: userInfo açarları sətirlərdir, enum deyil.
Delegate aydın kontrakt ilə bir-birə münasibət üçün seçin (tableView.delegate). Delegate daha sürətli və tip baxımından daha təhlükəsizdir. KVO modelin konkret xassəsindəki dəyişikliyi müşahidə etmək üçün seçin (isLoading, progress). KVO NSObject-dən miras tələb edir və debug zamanı çətinliklər yarada bilər (sehrli açar sətirləri). Müasir Swift-də Combine və async sequences hər üç yanaşmanı əvəz edir.
addObserver metodu iki abunə variantını dəstəkləyir: selector-based (ənənəvi) və block-based (closure ilə). Selector-based @objc uyğunluğu və müşahidəçinin əl ilə silinməsini tələb edir. Block-based (iOS 9+) capture list istifadə etməyə imkan verir və güclü istinadlar olmadan bloklardan istifadə edərkən OS tərəfindən avtomatik idarə olunur. Block-based həmçinin queue-ni dəstəkləyir — müşahidəçi bildirişi göstərilən növbədə alır.
Selektor vasitəsilə ənənəvi abunə üsulu. Handler metodu @objc ilə işarələnməli və optional Notification qəbul etməlidir. Üstünlük: legacy Objective-C də daxil olmaqla istənilən sinif tərəfindən istifadə imkanı. Çatışmazlıqlar: selektorun tip təhlükəsizliyinin olmaması, selektor adında səhv yazma riski, deinit-də məcburi removeObserver. Müşahidəçi obyektdən əvvəl silinərsə, handler çağırılmayacaq.
Block-based API bildiriş alındıqda icra olunan closure qəbul edir. queue parametri blokun hansı növbədə icra olunacağını müəyyən edir — UI yeniləmələri üçün main queue və ya məlumat emalı üçün background queue. Qaytarılan NSObjectProtocol dəyəri müşahidəçinin silinməsi üçün istifadə olunur: NotificationCenter.default.removeObserver(observer). Block-based müasir Swift-də üstünlük verilir.
protocol NotificationToken {
func dispose()
}
extension NotificationCenter {
func observe(
name: NSNotification.Name,
object: Any? = nil,
queue: OperationQueue? = .main,
using block: @escaping (Notification) -> Void
) -> NotificationToken {
let observer = addObserver(forName: name, object: object,
queue: queue, using: block)
return NotificationTokenWrapper(observer: observer, center: self)
}
}
// Avtomatik silinmə ilə istifadə
class ViewModel {
private var tokens: [NotificationToken] = []
func startObserving() {
let token = NotificationCenter.default.observe(
name: .dataDidUpdate,
queue: .main
) { [weak self] notification in
self?.handleUpdate(notification)
}
tokens.append(token)
}
deinit {
tokens.forEach { $0.dispose() }
}
}
Yaddaş sızmaları — NotificationCenter ilə işləyərkən əsas problemlərdən biri. Əgər müşahidəçi dealokasiyadan əvvəl silinməzsə, bildiriş göndərilərkən mərkəz artıq azad edilmiş obyektin metodunu çağırmağa çalışacaq, bu da EXC_BAD_ACCESS-a səbəb olacaq. iOS 9-dan etibarən, block-based addObserver zəif istinadlardan istifadə edir, lakin selector-based hələ də əl ilə removeObserver tələb edir. Best practice: müşahidəçini deinit-də silmək.
Selector-based: deinit-də mütləq NotificationCenter.default.removeObserver(self) çağırın. Əgər müşahidəçi bir neçə bildirişə abunədirsə, hamısını birdən (parametrsiz) və ya konkret adla silmək olar. Block-based: addObserver-dan alınan token ilə removeObserver vasitəsilə silin. iOS 9+ üçün block-based-də sızma baş vermir, lakin silinmə yenə də performans üçün tövsiyə olunur: azad edilmiş müşahidəçilər post zamanı gəzilməyəcək.
class SafeObserver {
private var observers: [NSObjectProtocol] = []
func addSubscriptions() {
let token1 = NotificationCenter.default.addObserver(
forName: .dataDidUpdate, object: nil,
queue: .main) { [weak self] _ in
self?.refreshData()
}
let token2 = NotificationCenter.default.addObserver(
forName: .userLoggedOut, object: nil,
queue: .main) { [weak self] _ in
self?.logout()
}
observers.append(contentsOf: [token1, token2])
}
deinit {
observers.forEach { NotificationCenter.default.removeObserver($0) }
}
private func refreshData() { }
private func logout() { }
}
Token nümunəsi müşahidəçilərin idarə edilməsini avtomatlaşdırır. Abunə zamanı token-obyekt (NSObjectProtocol) qaytarılır, o da dealokasiya zamanı avtomatik olaraq müşahidəçini silir. NotificationTokenWrapper NotificationCenter-ə və müşahidəçi tokeninə zəif istinad saxlayır, deinit-də removeObserver çağırır. Bu, NotificationCenter-i Combine yanaşmasına yaxınlaşdırır, burada AnyCancellable abunəliyin həyat dövrünü idarə edir.
Thread safety NotificationCenter zəmanət verir ki, post istənilən iplikdən çağırıla bilər və bütün müşahidəçilər bildirişi post-un çağırıldığı eyni iplikdə alacaqlar. Bu, çoxiplikli tətbiqlər üçün kritik əhəmiyyət daşıyır: əgər bildiriş fon ipliyindən göndərilibsə, handler-lər də fon ipliyində icra olunacaq. UI yeniləməsi üçün DispatchQueue.main.async vasitəsilə emalı main queue-ya göndərmək lazımdır.
NotificationCenter müxtəlif ipliklərdən post və addObserver çağırışları üçün iplik təhlükəsizdir. Daxili sinxronizasiya blokirovkadan istifadə edir, buna görə də bir neçə iplikdən tez-tez post çağırışları contention yarada bilər. Yüksək yüklü ssenarilər üçün (1000 faylın yüklənmə vəziyyəti) ayrıca bildiriş növbəsi və ya Combine publisher istifadə edin. postingStyle .now ilə NotificationQueue birbaşa post-a ekvivalentdir.
NotificationCenter Combine publisher-i NotificationCenter.default.publisher(for:object:) vasitəsilə dəstəkləyir. Publisher hər bir bildirişi Combine hadisəsinə çevirir, onu map, filter, debounce və throttle vasitəsilə transformasiya etmək olar. Bu, sinxron çatdırılma problemini həll edir: Combine bildirişləri göstərilən Scheduler-də asinxron emal edir. NotificationCenter.publisher — legacy mexanizm ilə müasir reaktiv proqramlaşdırma arasında körpüdür.
import Combine
class ReactiveViewModel {
private var cancellables = Set<AnyCancellable>()
func setupCombineSubscription() {
NotificationCenter.default
.publisher(for: .dataDidUpdate)
.receive(on: DispatchQueue.main)
.compactMap { $0.userInfo?["progress"] as? Float }
.debounce(for: .seconds(0.3), scheduler: RunLoop.main)
.sink { [weak self] progress in
self?.progressLabel.text = "\(Int(progress * 100))%"
}
.store(in: &cancellables)
}
}
Tez-tez verilən suallar
Bəli, NotificationCenter istənilən iplikdən post və addObserver çağırışları üçün iplik təhlükəsizdir. Lakin handler-lər post-un çağırıldığı eyni iplikdə icra olunur. UI yeniləməsi üçün block-based addObserver-da queue: .main və ya handler daxilində DispatchQueue.main.async istifadə edin. Combine publisher receive(on:) ilə də iplik problemini həll edir.
Selector-based: müşahidəçinin dealokasiyasından sonra bildiriş göndərilərkən EXC_BAD_ACCESS crash-i. Block-based (iOS 9+): zəif istinad sayəsində sızma yoxdur, lakin bildiriş mərkəzi aşkar removeObserver-a qədər bloku yaddaşda saxlamağa davam edir. Həmişə müşahidəçini deinit-də silmək və ya avtomatik idarə üçün Token nümunəsindən istifadə etmək tövsiyə olunur.
NotificationCenter — əlaqəsiz komponentlər arasında ixtiyari hadisələrin yayımı. KVO — konkret obyektin konkret xassəsindəki dəyişikliyin müşahidəsi. KVO NSObject-dən miras tələb edir və setter vasitəsilə xassə dəyişdikdə avtomatik xəbərdar edir. NotificationCenter yalnız aşkar post çağırışı zamanı xəbərdar edir. Modelin müşahidəsi üçün KVO və ya Combine üstünlük təşkil edir.
Tətbiq prosesi üçün bir default center. Əlavə mərkəzlər NotificationCenter() vasitəsilə yaradıla bilər, lakin praktikada ümumi default istifadə olunur. Hər bir mərkəz müstəqil işləyir — birində post digərinin müşahidəçilərinə çatdırılmır. Modulların izolyasiyası üçün bildiriş adlarının tərs-domen adları ilə ayrıca Name fəzalarından istifadə edin.
Qismən. Combine NotificationCenter.Publisher təqdim edir, o da NotificationCenter-i reaktiv axına bükür. Combine sinxronluq problemini həll edir (receive(on:) vasitəsilə), transformasiya operatorları və avtomatik abunə idarəetməsi (AnyCancellable) əlavə edir. Lakin NotificationCenter sistem iOS bildirişləri (UIApplication, UIKeyboard) və legacy kod üçün qalır. Combine əlavədir, əvəz deyil.
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