NotificationCenter — essens, funktionsprincip och notifikationsarkitektur

Författare: IT Sectr Publicerad: 2026-03-18 Lästid: 10 min

NotificationCenter — är en systemmekanism i iOS för att skicka och ta emot notifikationer mellan applikationskomponenter utan direkt koppling mellan avsändare och mottagare. Baserat på Observer-mönstret låter NotificationCenter objekt prenumerera på händelser och reagera asynkront. Enligt Apple Documentation (2025) stöder NSNotificationCenter både synkron sändning av notifikationer via post(name:object:) och fördröjd sändning via NotificationQueue. Notifikationscentret fungerar inom en process och korsar inte applikationsgränser.

Huvudpunkter

  • NotificationCenter — implementering av Observer-mönstret för händelseutbyte mellan iOS-komponenter.
  • addObserver prenumererar ett objekt på notifikationer med ett specifikt namn och avsändarobjekt.
  • post(name:object:) skickar notifikationen synkront till alla prenumererade observatörer.
  • removeObserver är obligatoriskt i deinit, annars uppstår en krasch vid sändning av notifikationen.
  • NotificationQueue gör det möjligt att fördröja notifikationer för asynkron leverans.

Vad är NotificationCenter?

NotificationCenter (NSNotificationCenter) — är en inbyggd iOS-mekanism för att implementera löst kopplad kommunikation mellan objekt. Observer-mönstret låter ett objekt (avsändare) meddela flera andra objekt (observatörer) om en händelse utan direkt referens till dem. NotificationCenter arbetar med tre entiteter: Notification.Name (notifikationsidentifierare), Notification (behållare med data) och NotificationCenter (dispatcher). Varje applikation har ett delat default center.

NSNotification och Notification.Name

Notification.Name — är en struktur som identifierar notifikationstypen. Skapas via extension Name: Notification.Name("MyNotification"). Notification — är ett objekt som innehåller name, object (avsändare) och userInfo (ordbok med data). Systemnotifikationer deklareras som konstanter: UIApplication.didBecomeActiveNotification, UIResponder.keyboardWillShowNotification. Anpassade notifikationer bör grupperas via extension för att undvika namnkollisioner. Namn bör vara omvänt-domän.

swift
// Definiera anpassade notifikationer
extension Notification.Name {
    static let dataDidUpdate =
        Notification.Name("com.app.dataDidUpdate")
    static let userLoggedOut =
        Notification.Name("com.app.userLoggedOut")
}

// Skicka notifikation med data
let userInfo: [String: Any] = [
    "userId": 123,
    "timestamp": Date()
]
NotificationCenter.default.post(
    name: .dataDidUpdate,
    object: nil,
    userInfo: userInfo
)

Lägga till observatör (addObserver)

Observatören prenumererar på en notifikation via metoden addObserver(_:selector:name:object:). Selector — metoden som anropas när notifikationen tas emot. Parametern object gör det möjligt att filtrera notifikationer från en specifik avsändare. Om object är nil tar observatören emot alla notifikationer med angivet namn från alla avsändare. Från och med iOS 9 kräver addObserver inte manuell borttagning för block-based API, men selector-based kräver fortfarande removeObserver.

swift
// Prenumerera på notifikation (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)
}

// Prenumerera på notifikation (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)
}

Hur fungerar NotificationCenter?

NotificationCenter lagrar en mappningstabell (name → uppsättning observatörer). När avsändaren anropar post(name:object:) går notifikationscentret synkront igenom alla observatörer som prenumererar på detta namn och anropar deras selektorer eller block. Nyckelegenskap: post blockerar den aktuella tråden tills alla handlare är klara. Om handlare utför tunga operationer fördröjer detta avsändaren. NotificationQueue löser detta problem genom att fördröja notifikationsleveransen.

Synkron sändning (post)

Metoden post(name:object:userInfo:) skickar notifikationen omedelbart till alla observatörer. Anropet är synkront — koden efter post körs först efter att alla handlare har slutförts. Anropsordningen för observatörer är inte garanterad och kan ändras mellan körningar. För sekventiell bearbetning, använd NotificationQueue med coalescing. Anropa inte post inuti en handlare för samma notifikation — detta leder till oändlig rekursion.

Fördröjd sändning (NotificationQueue)

NotificationQueue lägger till notifikationer i en kö för asynkron leverans. Stöder coalescing (sammanslagning av identiska notifikationer) och val av leveranskö (asap, idle, modal). Coalescing är användbart för frekventa händelser (laddningsförlopp), när endast det senaste värdet behöver meddelas. NotificationQueue använder run loop för aktivering, så fungerar endast i trådar med aktiv run loop.

swift
// Fördröjd sändning via NotificationQueue
let notification = Notification(
    name: .dataDidUpdate,
    object: self,
    userInfo: ["progress": 0.5]
)

// Coalescing: flera notifikationer slås samman till en
NotificationQueue.default.enqueue(
    notification,
    postingStyle: .whenIdle,
    coalesceMask: .onName,
    forModes: [.common]
)

// Asynkron sändning via DispatchQueue
DispatchQueue.main.async {
    NotificationCenter.default.post(name: .dataDidUpdate, object: nil)
}

Notification vs Delegate vs KVO

iOS tillhandahåller tre huvudmekanismer för kommunikation mellan objekt: NotificationCenter, Delegate och KVO (Key-Value Observing). Var och en löser notifikationsproblemet, men med olika avvägningar gällande koppling, prestanda och typsäkerhet. Valet av mekanism beror på relationen "en-till-en" eller "en-till-många" och behovet av dataöverföring.

EgenskapNotificationCenterDelegateKVO
KopplingLös (notifikationsnamn)Stark (protokoll)Medel (nyckel)
RelationEn-till-mångaEn-till-enEn-till-många
TypsäkerhetLåg (userInfo som Dictionary)Hög (protokollmetoder)Medel (Any?)
PrestandaMedel (tabellgenomgång)Hög (direkt anrop)Låg (NSObject)
AsynkronicitetSynkront (post blockerar)Synkront i avsändarens trådSynkront vid ändring

När välja NotificationCenter

NotificationCenter är idealiskt för händelser som flera oberoende komponenter måste reagera på. Exempel: ändring av appinställningar, användarens utloggning, mottagning av push-notifikation i bakgrunden. NotificationCenter passar även för löst kopplade moduler (funktion A behöver inte känna till funktion B). Nackdel — ingen typsäkerhet: userInfo-nycklar är strängar, inte enum.

När välja Delegate eller KVO

Delegate välj för en-till-en-relation med tydligt kontrakt (tableView.delegate). Delegate är snabbare och typsäkrare. KVO välj för att observera ändring av en specifik egenskap i en modell (isLoading, progress). KVO kräver arv från NSObject och kan orsaka svårigheter vid felsökning (magiska nyckelsträngar). I modern Swift ersätter Combine och async sequences alla tre tillvägagångssätten.

AddObserver: synkrona och asynkrona notifikationer

Metoden addObserver stöder två prenumerationsvarianter: selector-based (traditionell) och block-based (med closure). Selector-based kräver @objc-kompatibilitet och manuell borttagning av observatören. Block-based (iOS 9+) möjliggör användning av capture list och hanteras automatiskt av OS när block används utan starka referenser. Block-based stöder även queue — observatören tar emot notifikationen i den angivna kön.

Selector-based addObserver

Traditionellt sätt att prenumerera via selektor. Handlermetoden måste markeras med @objc och ta emot en valfri Notification. Fördel: kan användas av vilken klass som helst, inklusive legacy Objective-C. Nackdelar: brist på typsäkerhet för selektorn, risk för stavfel i selektorns namn, obligatorisk removeObserver i deinit. Om observatören tas bort före objektet anropas inte handlern.

Block-based addObserver

Block-based API tar emot en closure som körs när notifikationen tas emot. Parametern queue bestämmer i vilken kön blocket körs — main queue för UI-uppdateringar eller background queue för databearbetning. Det returnerade NSObjectProtocol-värdet används för att ta bort observatören: NotificationCenter.default.removeObserver(observer). Block-based föredras i modern Swift.

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

// Användning med automatisk borttagning
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() }
    }
}

Minneshantering och borttagning av observatörer

Minnesläckor — ett av huvudproblemen vid arbete med NotificationCenter. Om observatören inte tas bort före deallokering kommer centret vid sändning av notifikation att försöka anropa metoden för det redan frigjorda objektet, vilket leder till EXC_BAD_ACCESS. Från och med iOS 9 använder block-based addObserver svaga referenser, men selector-based kräver fortfarande manuell removeObserver. Best practice: ta bort observatören i deinit.

När ska removeObserver anropas

Selector-based: anropa obligatoriskt NotificationCenter.default.removeObserver(self) i deinit. Om observatören prenumererar på flera notifikationer kan alla tas bort på en gång (utan parametrar) eller en specifik efter namn. Block-based: ta bort via removeObserver med token från addObserver. För block-based på iOS 9+ uppstår ingen läcka, men borttagning rekommenderas ändå för prestanda: frigjorda observatörer kommer inte att genomsökas vid post.

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

Svaga referenser via Token-mönster

Token-mönstret automatiserar hanteringen av observatörer. Vid prenumeration returneras ett token-objekt (NSObjectProtocol) som vid deallokering automatiskt tar bort observatören. NotificationTokenWrapper lagrar en svag referens till NotificationCenter och observatörstoken, och anropar removeObserver i deinit. Detta närmar NotificationCenter till Combine-metoden, där AnyCancellable hanterar prenumerationens livscykel.

NotificationCenter i flertrådsmiljö

Thread safety NotificationCenter garanterar att post kan anropas från vilken tråd som helst och alla observatörer får notifikationen i samma tråd där post anropades. Detta är kritiskt för flertrådsapplikationer: om notifikationen skickades från en bakgrundstråd kommer handlare också att köras i bakgrundstråden. För UI-uppdatering måste bearbetningen skickas till main queue via DispatchQueue.main.async.

Trådsäkerhet för post och addObserver

NotificationCenter är trådsäkert för anrop av post och addObserver från olika trådar. Intern synkronisering använder låsning, så frekventa post från flera trådar kan skapa contention. För scenarier med hög belastning (laddningsförlopp för 1000 filer) använd en separat notifikationskö eller Combine publisher. NotificationQueue med postingStyle .now motsvarar direkt post.

Asynkron leverans via Combine

NotificationCenter stöder Combine publisher via NotificationCenter.default.publisher(for:object:). Publisher omvandlar varje notifikation till en Combine-händelse som kan transformeras via map, filter, debounce och throttle. Detta löser problemet med synkron leverans: Combine bearbetar notifikationer asynkront på en angiven Scheduler. NotificationCenter.publisher — är en bro mellan legacy-mekanismen och modern reaktiv programmering.

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

Vanliga frågor

Är NotificationCenter trådsäkert?

Ja, NotificationCenter är trådsäkert för anrop av post och addObserver från vilka trådar som helst. Dock körs handlare i samma tråd där post anropades. För UI-uppdatering använd queue: .main i block-based addObserver eller DispatchQueue.main.async inuti handlern. Combine publisher med receive(on:) löser också trådproblemet.

Vad händer om observatören inte tas bort?

Selector-based: krasch EXC_BAD_ACCESS vid sändning av notifikation efter deallokering av observatören. Block-based (iOS 9+): ingen läcka tack vare svag referens, men notifikationscentret fortsätter att hålla blocket i minnet tills explicit removeObserver. Rekommenderas att alltid ta bort observatören i deinit eller använda Token-mönstret för automatisk hantering.

Vad är skillnaden mellan NotificationCenter och KVO?

NotificationCenter — sändning av godtyckliga händelser mellan orelaterade komponenter. KVO — observation av ändring av en specifik egenskap hos ett specifikt objekt. KVO kräver arv från NSObject och meddelar automatiskt vid egenskapsändring via setter. NotificationCenter meddelar endast vid explicit anrop av post. För modellobservation är KVO eller Combine att föredra.

Hur många NotificationCenter finns i en applikation?

Ett default center per applikationsprocess. Ytterligare center kan skapas via NotificationCenter(), men i praktiken används det delade default. Varje center fungerar oberoende — post i ett center levereras inte till observatörer i ett annat. För modulisolering, använd separata Name-namnrymder via omvänt-domän notifikationsnamn.

Ersätter Combine NotificationCenter?

Delvis. Combine tillhandahåller NotificationCenter.Publisher som omsluter NotificationCenter i en reaktiv ström. Combine löser synkronitetsproblemet (via receive(on:)), lägger till transformationsoperatorer och automatisk prenumerationshantering (AnyCancellable). Dock kvarstår NotificationCenter för iOS-systemnotifikationer (UIApplication, UIKeyboard) och legacy-kod. Combine är ett tillägg, inte en ersättning.

Sammanfattning

  • NotificationCenter — implementering av Observer-mönstret för löst kopplad "en-till-många"-kommunikation i iOS.
  • post skickar notifikationen synkront till alla observatörer i den aktuella tråden, blockerar avsändaren.
  • addObserver stöder selector-based (med @objc) och block-based (med capture list och queue) prenumeration.
  • removeObserver är obligatoriskt i deinit för selector-based prenumerationer, annars krasch.
  • NotificationQueue tillhandahåller fördröjd leverans med coalescing för frekventa händelser.
  • Thread safety garanterar funktion från vilken tråd som helst, men handlare körs i avsändarens tråd.
  • Använd Token-mönstret eller Combine publisher för säker och modern prenumerationshantering.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också