NotificationCenter, gönderen ve alıcı arasında doğrudan bağlantı olmadan uygulama bileşenleri arasında bildirim göndermek ve almak için iOS'ta bir sistem mekanizmasıdır. Observer desenine dayanan NotificationCenter, nesnelerin olaylara abone olmasına ve bunlara asenkron olarak yanıt vermesine olanak tanır. Apple Documentation'a (2025) göre NSNotificationCenter, post(name:object:) aracılığıyla senkron bildirim göndermeyi ve NotificationQueue aracılığıyla gecikmeli göndermeyi destekler. Bildirim merkezi tek bir işlem içinde çalışır ve uygulama sınırlarını aşmaz.
Kilit Noktalar
NotificationCenter (NSNotificationCenter), nesneler arasında gevşek bağlı iletişim uygulamak için yerleşik bir iOS mekanizmasıdır. Observer deseni, bir nesnenin (gönderen), doğrudan bir referans olmadan birden çok diğer nesneye (gözlemci) bir olay hakkında bildirimde bulunmasına olanak tanır. NotificationCenter üç varlıkla çalışır: Notification.Name (bildirim tanımlayıcı), Notification (veri içeren kap) ve NotificationCenter (dağıtıcı). Her uygulamanın paylaşılan bir default center'ı vardır.
Notification.Name, bildirim türünü tanımlayan bir yapıdır. extension Name: Notification.Name(“MyNotification”) ile oluşturulur. Notification, name, object (gönderen) ve userInfo (veri içeren sözlük) içeren bir nesnedir. Sistem bildirimleri sabit olarak bildirilir: UIApplication.didBecomeActiveNotification, UIResponder.keyboardWillShowNotification. Özel bildirimler, ad çakışmalarını önlemek için extension aracılığıyla gruplandırılmalıdır. İsimler ters alan adı biçiminde olmalıdır.
// Özel bildirimler tanımlama
extension Notification.Name {
static let dataDidUpdate =
Notification.Name("com.app.dataDidUpdate")
static let userLoggedOut =
Notification.Name("com.app.userLoggedOut")
}
// Veriyle bildirim gönderme
let userInfo: [String: Any] = [
"userId": 123,
"timestamp": Date()
]
NotificationCenter.default.post(
name: .dataDidUpdate,
object: nil,
userInfo: userInfo
)
Gözlemci, addObserver(_:selector:name:object:) yöntemi aracılığıyla bir bildirime abone olur. Selector, bildirim alındığında çağrılacak yöntemdir. object parametresi, belirli bir gönderenden gelen bildirimleri filtrelemeye olanak tanır. object nil ise, gözlemci herhangi bir gönderenden belirtilen ada sahip tüm bildirimleri alır. iOS 9'dan itibaren addObserver, block-based API için manuel kaldırma gerektirmez, ancak selector-based hala removeObserver gerektirir.
// Bir bildirime abone olma (selector tabanlı)
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)
}
// Bir bildirime abone olma (block tabanlı, 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 bir eşleme tablosu (ad → gözlemci kümesi) saklar. Gönderen post(name:object:) çağırdığında, bildirim merkezi senkron olarak bu ada abone olan tüm gözlemcileri dolaşır ve seçicilerini veya bloklarını çağırır. Kilit özellik: post, tüm işleyiciler tamamlanana kadar geçerli iş parçacığını bloklar. İşleyiciler ağır işlemler yaparsa, bu göndereni geciktirir. NotificationQueue, bildirim teslimatını erteleyerek bu sorunu çözer.
post(name:object:userInfo:) yöntemi, tüm gözlemcilere hemen bir bildirim gönderir. Çağrı senkronizedir — post'tan sonraki kod, yalnızca tüm işleyiciler tamamlandıktan sonra yürütülür. Gözlemcilerin çağrılma sırası garanti edilmez ve çalıştırmalar arasında değişebilir. Sıralı işleme için coalescing ile NotificationQueue kullanın. Aynı bildirimin işleyicisi içinde post çağırmayın — bu sonsuz özyinelemeye yol açar.
NotificationQueue, asenkron teslimat için bildirimleri bir kuyruğa ekler. Coalescing (aynı bildirimleri birleştirme) ve teslimat kuyruğu seçimini (asap, idle, modal) destekler. Coalescing, yalnızca son değerle bildirimde bulunmanız gereken sık olaylar (indirme ilerlemesi) için kullanışlıdır. NotificationQueue, ateşlemek için run loop kullanır, bu nedenle yalnızca etkin run loop'a sahip iş parçacıklarında çalışır.
// NotificationQueue ile gecikmeli gönderme
let notification = Notification(
name: .dataDidUpdate,
object: self,
userInfo: ["progress": 0.5]
)
// Coalescing: birden çok bildirim birleştirilir
NotificationQueue.default.enqueue(
notification,
postingStyle: .whenIdle,
coalesceMask: .onName,
forModes: [.common]
)
// DispatchQueue ile asenkron teslimat
DispatchQueue.main.async {
NotificationCenter.default.post(name: .dataDidUpdate, object: nil)
}
iOS, nesneler arasında iletişim için üç ana mekanizma sağlar: NotificationCenter, Delegate ve KVO (Key-Value Observing). Her biri bildirim sorununu çözer ancak bağlantı, performans ve tür güvenliği konularında farklı ödünleşimlerle birlikte gelir. Mekanizma seçimi, bire-bir veya bire-çok ilişkisine ve veri aktarımı ihtiyacına bağlıdır.
| Özellik | NotificationCenter | Delegate | KVO |
|---|---|---|---|
| Bağlantı | Zayıf (bildirim adı) | Güçlü (protokol) | Orta (anahtar) |
| İlişki | Bire-çok | Bire-bir | Bire-çok |
| Tür güvenliği | Düşük (userInfo Dictionary olarak) | Yüksek (protokol yöntemleri) | Orta (Any?) |
| Performans | Orta (tablo dolaşımı) | Yüksek (doğrudan çağrı) | Düşük (NSObject) |
| Eşzamansızlık | Senkron (post bloklar) | Gönderenin iş parçacığında senkron | Değişiklikte senkron |
NotificationCenter, birden çok bağımsız bileşenin yanıt vermesi gereken olaylar için idealdir. Örnekler: uygulama ayarları değişiklikleri, kullanıcı çıkışı, arka planda push bildirimi alma. NotificationCenter ayrıca gevşek bağlı modüller için de uygundur (A özelliği B özelliğini bilmemelidir). Dezavantajı, tür güvenliği eksikliğidir: userInfo anahtarları enum değil, dizelerdir.
Delegate, net bir sözleşmeye (tableView.delegate) sahip bire-bir ilişkiler için tercihtir. Delegate daha hızlı ve türler açısından daha güvenlidir. KVO, modelin belirli bir özelliğindeki (isLoading, progress) değişiklikleri gözlemlemek için tercihtir. KVO, NSObject'ten kalıtım gerektirir ve hata ayıklamada zorluklara neden olabilir (sihirli dize anahtarları). Modern Swift'te, Combine ve async dizileri her üç yaklaşımın da yerini alır.
addObserver yöntemi iki abonelik çeşidini destekler: selector-based (geleneksel) ve block-based (closure ile). Selector-based, @objc uyumluluğu ve manuel gözlemci kaldırma gerektirir. Block-based (iOS 9+), bir capture list kullanımına izin verir ve güçlü referanslar olmadan bloklar kullanıldığında işletim sistemi tarafından otomatik olarak yönetilir. Block-based ayrıca queue'yu da destekler — gözlemci, belirtilen kuyrukta bildirimi alır.
Selector aracılığıyla geleneksel abonelik yöntemi. İşleyici yöntemi @objc ile işaretlenmeli ve isteğe bağlı bir Notification kabul etmelidir. Avantajı: eski Objective-C dahil herhangi bir sınıf tarafından kullanılabilir. Dezavantajları: seçicinin tür güvenliği eksikliği, seçici adında yazım hatası riski, deinit'te zorunlu removeObserver. Gözlemci nesneden önce kaldırılırsa, işleyici çağrılmaz.
Block-based API, bildirim alındığında yürütülen bir closure kabul eder. queue parametresi, bloğun hangi kuyrukta çalıştırılacağını belirler — UI güncellemeleri için ana kuyruk veya veri işleme için arka plan kuyruğu. Dönüş değeri NSObjectProtocol, gözlemciyi kaldırmak için kullanılır: NotificationCenter.default.removeObserver(observer). Modern Swift'te block-based tercih edilir.
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)
}
}
// Otomatik kaldırma ile kullanma
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() }
}
}
Bellek sızıntıları, NotificationCenter ile çalışırken ana sorunlardan biridir. Bir gözlemci, ayrılmadan önce kaldırılmazsa, bildirim gönderilirken merkez, zaten ayrılmış bir nesnede bir yöntem çağırmaya çalışarak EXC_BAD_ACCESS'e neden olur. iOS 9'dan itibaren block-based addObserver zayıf referanslar kullanır, ancak selector-based hala manuel removeObserver gerektirir. En iyi uygulama: gözlemciyi deinit içinde kaldırın.
Selector-based: deinit içinde her zaman NotificationCenter.default.removeObserver(self) çağrısı yapın. Gözlemci birden çok bildirime abone ise, hepsini bir kerede (parametresiz) veya ada göre belirli birini kaldırabilirsiniz. Block-based: addObserver'dan döndürülen token ile removeObserver aracılığıyla kaldırın. iOS 9+ üzerinde block-based için sızıntı olmaz, ancak performans için kaldırma yine de önerilir: ayrılmış gözlemciler post sırasında dolaşılmaz.
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 deseni, gözlemci yönetimini otomatikleştirir. Abonelikte, ayrılma sırasında otomatik olarak gözlemciyi kaldıran bir token nesnesi (NSObjectProtocol) döndürülür. NotificationTokenWrapper, NotificationCenter ve gözlemci token'ına zayıf bir referans saklar ve deinit içinde removeObserver'ı çağırır. Bu, NotificationCenter'ı AnyCancellable'ın abonelik yaşam döngüsünü yönettiği Combine yaklaşımına yaklaştırır.
İş parçacığı güvenliği: NotificationCenter, post'un herhangi bir iş parçacığından çağrılabileceğini ve tüm gözlemcilerin bildirimi, post'un çağrıldığı aynı iş parçacığında alacağını garanti eder. Bu, çok iş parçacıklı uygulamalar için kritiktir: bir arka plan iş parçacığından bildirim gönderilirse, işleyiciler de arka plan iş parçacığında yürütülür. UI güncellemeleri için, DispatchQueue.main.async aracılığıyla işlemeyi ana kuyruğa gönderin.
NotificationCenter, farklı iş parçacıklarından post ve addObserver çağrıları için iş parçacığı güvenlidir. Dahili senkronizasyon kilitleme kullanır, bu nedenle birden çok iş parçacığından sık post çağrıları çekişme yaratabilir. Yüksek yük senaryoları (1000 dosyanın indirme ilerlemesi) için ayrı bir bildirim kuyruğu veya Combine yayıncısı kullanın. postingStyle .now ile NotificationQueue, doğrudan post ile eşdeğerdir.
NotificationCenter, NotificationCenter.default.publisher(for:object:) aracılığıyla Combine yayıncısını destekler. Publisher, her bildirimi map, filter, debounce ve throttle ile dönüştürülebilen bir Combine olayına dönüştürür. Bu, senkron teslimat sorununu çözer: Combine, bildirimleri belirtilen Zamanlayıcıda asenkron olarak işler. NotificationCenter.publisher, eski mekanizma ile modern reaktif programlama arasında bir köprü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)
}
}
Sıkça Sorulan Sorular
Evet, NotificationCenter herhangi bir iş parçacığından post ve addObserver çağrıları için iş parçacığı güvenlidir. Ancak işleyiciler, post'un çağrıldığı aynı iş parçacığında yürütülür. UI güncellemeleri için block-based addObserver'da queue: .main kullanın veya işleyici içinde DispatchQueue.main.async kullanın. receive(on:) ile Combine yayıncısı da iş parçacığı sorununu çözer.
Selector-based: gözlemcinin ayrılmasından sonra bildirim gönderirken EXC_BAD_ACCESS çökmesi. Block-based (iOS 9+): zayıf referans sayesinde sızıntı olmaz, ancak bildirim merkezi, açık removeObserver'a kadar bloğu bellekte tutmaya devam eder. Her zaman deinit'te gözlemciyi kaldırmanız veya otomatik yönetim için Token desenini kullanmanız önerilir.
NotificationCenter, ilgisiz bileşenler arasında rastgele olaylar için bir yayın mekanizmasıdır. KVO, belirli bir nesnenin belirli bir özelliğindeki değişiklikleri gözlemler. KVO, NSObject kalıtımı gerektirir ve setter aracılığıyla özellik değişikliklerinde otomatik olarak bildirir. NotificationCenter yalnızca post açıkça çağrıldığında bildirir. Model gözlemi için KVO veya Combine tercih edilir.
Uygulama işlemi başına bir default center. NotificationCenter() aracılığıyla ek merkezler oluşturulabilir, ancak pratikte paylaşılan default kullanılır. Her merkez bağımsız çalışır — birindeki post diğerinin gözlemcilerine iletilmez. Modül yalıtımı için, ters alan adlı bildirim adları aracılığıyla ayrı Name ad alanları kullanın.
Kısmen. Combine, NotificationCenter'ı reaktif bir akışa saran NotificationCenter.Publisher sağlar. Combine, senkronizasyon sorununu (receive(on:) aracılığıyla) çözer, dönüşüm operatörleri ve otomatik abonelik yönetimi (AnyCancellable) ekler. Ancak NotificationCenter, iOS sistem bildirimleri (UIApplication, UIKeyboard) ve eski kod için kalır. Combine bir iyileştirmedir, bir yenileme değildir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun