NotificationCenter — Wesen, Funktionsweise und Benachrichtigungsarchitektur

Autor: IT Sectr Veröffentlicht: 2026-03-18 Lesezeit: 10 Min.

NotificationCenter ist ein Systemmechanismus in iOS zum Senden und Empfangen von Benachrichtigungen zwischen Anwendungskomponenten ohne direkte Verbindung zwischen Sender und Empfänger. Basierend auf dem Observer-Muster ermöglicht NotificationCenter Objekten, Ereignisse zu abonnieren und asynchron darauf zu reagieren. Laut Apple Documentation (2025) unterstützt NSNotificationCenter sowohl das synchrone Senden von Benachrichtigungen über post(name:object:) als auch das verzögerte Senden über NotificationQueue. Das Benachrichtigungscenter arbeitet innerhalb eines einzelnen Prozesses und überschreitet keine Anwendungsgrenzen.

Wichtige Punkte

  • NotificationCenter — eine Implementierung des Observer-Musters zum Austausch von Ereignissen zwischen iOS-Komponenten.
  • addObserver abonniert ein Objekt für Benachrichtigungen mit einem bestimmten Namen und Senderobjekt.
  • post(name:object:) sendet eine Benachrichtigung synchron an alle abonnierten Beobachter.
  • removeObserver muss in deinit aufgerufen werden, sonst kommt es beim Senden der Benachrichtigung zu einem Crash.
  • NotificationQueue ermöglicht das Verzögern von Benachrichtigungen für die asynchrone Zustellung.

Was ist NotificationCenter?

NotificationCenter (NSNotificationCenter) ist ein integrierter iOS-Mechanismus zur Implementierung von lose gekoppelter Kommunikation zwischen Objekten. Das Observer-Muster ermöglicht es einem Objekt (Sender), mehrere andere Objekte (Beobachter) über ein Ereignis zu benachrichtigen, ohne einen direkten Verweis auf sie zu haben. NotificationCenter arbeitet mit drei Entitäten: Notification.Name (Benachrichtigungskennung), Notification (Container mit Daten) und NotificationCenter (Dispatcher). Jede Anwendung hat ein gemeinsames default center.

NSNotification und Notification.Name

Notification.Name ist eine Struktur, die den Benachrichtigungstyp identifiziert. Erstellt über extension Name: Notification.Name(“MyNotification”). Notification ist ein Objekt, das name, object (Sender) und userInfo (Wörterbuch mit Daten) enthält. Systembenachrichtigungen werden als Konstanten deklariert: UIApplication.didBecomeActiveNotification, UIResponder.keyboardWillShowNotification. Benutzerdefinierte Benachrichtigungen sollten über extension gruppiert werden, um Namenskollisionen zu vermeiden. Namen sollten Reverse-Domain sein.

swift
// Definieren von benutzerdefinierten Benachrichtigungen
extension Notification.Name {
    static let dataDidUpdate =
        Notification.Name("com.app.dataDidUpdate")
    static let userLoggedOut =
        Notification.Name("com.app.userLoggedOut")
}

// Senden einer Benachrichtigung mit Daten
let userInfo: [String: Any] = [
    "userId": 123,
    "timestamp": Date()
]
NotificationCenter.default.post(
    name: .dataDidUpdate,
    object: nil,
    userInfo: userInfo
)

Hinzufügen eines Beobachters (addObserver)

Ein Beobachter abonniert eine Benachrichtigung über die Methode addObserver(_:selector:name:object:). Selector ist die Methode, die beim Empfang der Benachrichtigung aufgerufen wird. Der Parameter object ermöglicht das Filtern von Benachrichtigungen eines bestimmten Senders. Wenn object nil ist, empfängt der Beobachter alle Benachrichtigungen mit dem angegebenen Namen von jedem Sender. Seit iOS 9 erfordert addObserver für die block-based API keine manuelle Entfernung, aber selector-based erfordert weiterhin removeObserver.

swift
// Abonnieren einer Benachrichtigung (selector-basiert)
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)
}

// Abonnieren einer Benachrichtigung (block-basiert, 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)
}

Wie funktioniert NotificationCenter?

NotificationCenter speichert eine Zuordnungstabelle (Name → Menge der Beobachter). Wenn der Sender post(name:object:) aufruft, durchläuft das Benachrichtigungscenter synchron alle für diesen Namen abonnierten Beobachter und ruft deren Selectoren oder Blöcke auf. Wichtiges Merkmal: post blockiert den aktuellen Thread, bis alle Handler abgeschlossen sind. Wenn Handler schwere Operationen ausführen, verzögert dies den Sender. NotificationQueue löst dieses Problem, indem es die Zustellung von Benachrichtigungen verzögert.

Synchrone Zustellung (post)

Die Methode post(name:object:userInfo:) sendet eine Benachrichtigung sofort an alle Beobachter. Der Aufruf ist synchron — Code nach post wird erst ausgeführt, nachdem alle Handler abgeschlossen sind. Die Reihenfolge des Aufrufs der Beobachter ist nicht garantiert und kann zwischen Starts variieren. Für die sequenzielle Verarbeitung verwenden Sie NotificationQueue mit Coalescing. Rufen Sie post nicht innerhalb eines Handlers für dieselbe Benachrichtigung auf — dies führt zu unendlicher Rekursion.

Verzögerte Zustellung (NotificationQueue)

NotificationQueue fügt Benachrichtigungen zur asynchronen Zustellung in eine Warteschlange ein. Es unterstützt Coalescing (Zusammenführen identischer Benachrichtigungen) und die Auswahl der Zustellungswarteschlange (asap, idle, modal). Coalescing ist nützlich für häufige Ereignisse (Download-Fortschritt), wenn Sie nur mit dem letzten Wert benachrichtigen müssen. NotificationQueue verwendet die Run Loop zum Auslösen, funktioniert daher nur in Threads mit aktiver Run Loop.

swift
// Verzögerte Zustellung über NotificationQueue
let notification = Notification(
    name: .dataDidUpdate,
    object: self,
    userInfo: ["progress": 0.5]
)

// Coalescing: mehrere Benachrichtigungen werden zu einer zusammengeführt
NotificationQueue.default.enqueue(
    notification,
    postingStyle: .whenIdle,
    coalesceMask: .onName,
    forModes: [.common]
)

// Asynchrone Zustellung über DispatchQueue
DispatchQueue.main.async {
    NotificationCenter.default.post(name: .dataDidUpdate, object: nil)
}

Notification vs Delegate vs KVO

iOS bietet drei Hauptmechanismen für die Kommunikation zwischen Objekten: NotificationCenter, Delegate und KVO (Key-Value Observing). Jeder löst das Benachrichtigungsproblem, jedoch mit unterschiedlichen Kompromissen bei Kopplung, Leistung und Typsicherheit. Die Wahl des Mechanismus hängt von der Eins-zu-Eins- oder Eins-zu-Viele-Beziehung und der Notwendigkeit der Datenübertragung ab.

EigenschaftNotificationCenterDelegateKVO
KopplungSchwach (Benachrichtigungsname)Stark (Protokoll)Mittel (Schlüssel)
BeziehungEins-zu-VieleEins-zu-EinsEins-zu-Viele
TypsicherheitNiedrig (userInfo als Dictionary)Hoch (Protokollmethoden)Mittel (Any?)
LeistungMittel (Tabellendurchlauf)Hoch (direkter Aufruf)Niedrig (NSObject)
AsynchronitätSynchron (post blockiert)Synchron im Thread des SendersSynchron bei Änderung

Wann NotificationCenter wählen

NotificationCenter ist ideal für Ereignisse, auf die mehrere unabhängige Komponenten reagieren müssen. Beispiele: Änderungen der Anwendungseinstellungen, Benutzerabmeldung, Empfangen einer Push-Benachrichtigung im Hintergrund. NotificationCenter eignet sich auch für lose gekoppelte Module (Feature A sollte nichts von Feature B wissen). Der Nachteil ist der Mangel an Typsicherheit: userInfo-Schlüssel sind Strings, keine Enums.

Wann Delegate oder KVO wählen

Delegate ist die Wahl für Eins-zu-Eins-Beziehungen mit einem klaren Vertrag (tableView.delegate). Delegate ist schneller und typsicherer. KVO ist die Wahl zur Überwachung von Änderungen einer bestimmten Modelleigenschaft (isLoading, progress). KVO erfordert Vererbung von NSObject und kann Debugging-Schwierigkeiten verursachen (magische String-Schlüssel). In modernem Swift ersetzen Combine und async-Sequenzen alle drei Ansätze.

AddObserver: synchrone und asynchrone Benachrichtigungen

Die Methode addObserver unterstützt zwei Abonnementvarianten: selector-based (traditionell) und block-based (mit Closure). Selector-based erfordert @objc-Kompatibilität und manuelles Entfernen des Beobachters. Block-based (iOS 9+) ermöglicht die Verwendung einer Capture-List und wird vom OS automatisch verwaltet, wenn Blöcke ohne starke Referenzen verwendet werden. Block-based unterstützt auch queue — der Beobachter erhält die Benachrichtigung in der angegebenen Warteschlange.

Selector-based addObserver

Die traditionelle Methode des Abonnierens über einen Selector. Die Handler-Methode muss mit @objc markiert sein und ein optionales Notification akzeptieren. Vorteil: Kann von jeder Klasse verwendet werden, einschließlich Legacy-Objective-C. Nachteile: Fehlende Typsicherheit des Selectors, Risiko von Tippfehlern im Selectornamen, obligatorisches removeObserver in deinit. Wenn der Beobachter vor dem Objekt entfernt wird, wird der Handler nicht aufgerufen.

Block-based addObserver

Die block-based API akzeptiert einen Closure, der beim Empfang der Benachrichtigung ausgeführt wird. Der queue-Parameter bestimmt, in welcher Warteschlange der Block ausgeführt wird — der Hauptwarteschlange für UI-Updates oder einer Hintergrundwarteschlange für die Datenverarbeitung. Der Rückgabewert NSObjectProtocol wird zum Entfernen des Beobachters verwendet: NotificationCenter.default.removeObserver(observer). Block-based wird in modernem Swift bevorzugt.

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

// Verwendung mit automatischer Entfernung
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() }
    }
}

Speicherverwaltung und Entfernen von Beobachtern

Speicherlecks sind eines der Hauptprobleme bei der Arbeit mit NotificationCenter. Wenn ein Beobachter vor der Freigabe nicht entfernt wird, versucht das Center beim Senden einer Benachrichtigung, eine Methode auf einem bereits freigegebenen Objekt aufzurufen, was zu EXC_BAD_ACCESS führt. Seit iOS 9 verwendet block-based addObserver schwache Referenzen, aber selector-based erfordert weiterhin manuelles removeObserver. Best Practice: Entfernen Sie den Beobachter in deinit.

Wann removeObserver aufrufen

Selector-based: Rufen Sie immer NotificationCenter.default.removeObserver(self) in deinit auf. Wenn der Beobachter mehrere Benachrichtigungen abonniert hat, können Sie alle auf einmal (ohne Parameter) oder eine bestimmte nach Namen entfernen. Block-based: Entfernen Sie über removeObserver mit dem von addObserver zurückgegebenen Token. Für block-based auf iOS 9+ tritt kein Speicherleck auf, aber die Entfernung wird dennoch aus Leistungsgründen empfohlen: Freigegebene Beobachter werden während post nicht durchlaufen.

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

Schwache Referenzen durch Token-Muster

Das Token-Muster automatisiert die Beobachterverwaltung. Beim Abonnieren wird ein Token-Objekt (NSObjectProtocol) zurückgegeben, das bei Freigabe automatisch den Beobachter entfernt. NotificationTokenWrapper speichert eine schwache Referenz auf NotificationCenter und den Beobachter-Token und ruft removeObserver in deinit auf. Dies bringt NotificationCenter näher an den Combine-Ansatz, bei dem AnyCancellable den Abonnement-Lebenszyklus verwaltet.

NotificationCenter in einer Multithread-Umgebung

Threadsicherheit: NotificationCenter garantiert, dass post von jedem Thread aus aufgerufen werden kann und alle Beobachter die Benachrichtigung im selben Thread erhalten, in dem post aufgerufen wurde. Dies ist kritisch für Multithread-Anwendungen: Wenn eine Benachrichtigung aus einem Hintergrundthread gesendet wird, werden die Handler ebenfalls im Hintergrundthread ausgeführt. Für UI-Updates dispatchen Sie die Verarbeitung über DispatchQueue.main.async an die Hauptwarteschlange.

Threadsicherheit von post und addObserver

NotificationCenter ist threadsicher für post- und addObserver-Aufrufe aus verschiedenen Threads. Die interne Synchronisation verwendet Sperren, daher können häufige posts aus mehreren Threads zu Konflikten führen. Für Hochlastszenarien (Download-Fortschritt von 1000 Dateien) verwenden Sie eine separate Benachrichtigungswarteschlange oder einen Combine-Publisher. NotificationQueue mit postingStyle .now entspricht direktem post.

Asynchrone Zustellung durch Combine

NotificationCenter unterstützt Combine-Publisher über NotificationCenter.default.publisher(for:object:). Publisher verwandelt jede Benachrichtigung in ein Combine-Ereignis, das durch map, filter, debounce und throttle transformiert werden kann. Dies löst das Problem der synchronen Zustellung: Combine verarbeitet Benachrichtigungen asynchron auf dem angegebenen Scheduler. NotificationCenter.publisher ist eine Brücke zwischen dem Legacy-Mechanismus und moderner reaktiver Programmierung.

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

Häufig gestellte Fragen

Ist NotificationCenter threadsicher?

Ja, NotificationCenter ist threadsicher für post- und addObserver-Aufrufe aus jedem Thread. Allerdings werden die Handler im selben Thread ausgeführt, in dem post aufgerufen wurde. Für UI-Updates verwenden Sie queue: .main im block-based addObserver oder DispatchQueue.main.async innerhalb des Handlers. Combine-Publisher mit receive(on:) löst ebenfalls das Thread-Problem.

Was passiert, wenn ich den Beobachter nicht entferne?

Selector-based: Crash EXC_BAD_ACCESS beim Senden einer Benachrichtigung nach der Freigabe des Beobachters. Block-based (iOS 9+): Kein Speicherleck dank schwacher Referenz, aber das Benachrichtigungscenter behält den Block bis zum expliziten removeObserver im Speicher. Es wird empfohlen, den Beobachter immer in deinit zu entfernen oder das Token-Muster zur automatischen Verwaltung zu verwenden.

Was ist der Unterschied zwischen NotificationCenter und KVO?

NotificationCenter ist ein Broadcast-Mechanismus für beliebige Ereignisse zwischen nicht verwandten Komponenten. KVO beobachtet Änderungen einer bestimmten Eigenschaft eines bestimmten Objekts. KVO erfordert NSObject-Vererbung und benachrichtigt automatisch bei Eigenschaftsänderungen über setter. NotificationCenter benachrichtigt nur bei explizitem post-Aufruf. Für die Modellbeobachtung ist KVO oder Combine vorzuziehen.

Wie viele NotificationCenter gibt es in einer Anwendung?

Ein default center pro Anwendungsprozess. Zusätzliche Center können über NotificationCenter() erstellt werden, aber in der Praxis wird das gemeinsame default verwendet. Jedes Center arbeitet unabhängig — post in einem wird nicht an Beobachter eines anderen zugestellt. Verwenden Sie zur Modulisolierung separate Name-Namensräume durch Reverse-Domain-Benachrichtigungsnamen.

Ersetzt Combine NotificationCenter?

Teilweise. Combine stellt NotificationCenter.Publisher bereit, der NotificationCenter in einen reaktiven Strom einhüllt. Combine löst das Synchronitätsproblem (über receive(on:)), fügt Transformationsoperatoren und automatische Abonnementverwaltung (AnyCancellable) hinzu. NotificationCenter bleibt jedoch für iOS-Systembenachrichtigungen (UIApplication, UIKeyboard) und Legacy-Code bestehen. Combine ist eine Erweiterung, kein Ersatz.

Zusammenfassung

  • NotificationCenter — eine Implementierung des Observer-Musters für lose gekoppelte Eins-zu-Viele-Kommunikation in iOS.
  • post sendet eine Benachrichtigung synchron an alle Beobachter im aktuellen Thread und blockiert den Sender.
  • addObserver unterstützt selector-based (mit @objc) und block-based (mit Capture-List und queue) Abonnements.
  • removeObserver ist für selector-based Abonnements in deinit obligatorisch, sonst Crash.
  • NotificationQueue bietet verzögerte Zustellung mit Coalescing für häufige Ereignisse.
  • Threadsicherheit garantiert Betrieb von jedem Thread, aber Handler werden im Thread des Senders ausgeführt.
  • Verwenden Sie das Token-Muster oder den Combine-Publisher für sicheres und modernes Abonnementmanagement.

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch