NotificationCenter — lényeg, működési elv és az értesítések architektúrája

Szerző: IT Sectr Megjelenés: 2026-03-18 Olvasási idő: 10 perc

NotificationCenter — egy iOS rendszermechanizmus az alkalmazáskomponensek közötti értesítések küldésére és fogadására a feladó és a vevő közötti közvetlen kapcsolat nélkül. Az Observer mintára épülve a NotificationCenter lehetővé teszi az objektumok számára, hogy feliratkozzanak eseményekre és aszinkron módon reagáljanak rájuk. Az Apple Documentation (2025) szerint az NSNotificationCenter támogatja az értesítések szinkron küldését a post(name:object:) segítségével, valamint a késleltetett küldést a NotificationQueue-n keresztül. Az értesítési központ egyetlen folyamaton belül működik, és nem lépi át az alkalmazások határait.

Főbb pontok

  • NotificationCenter — az Observer minta megvalósítása az iOS komponensek közötti eseménycseréhez.
  • addObserver feliratkoztat egy objektumot értesítésekre egy adott névvel és feladó objektummal.
  • post(name:object:) szinkron módon küldi el az értesítést az összes feliratkozott megfigyelőnek.
  • removeObserver kötelező a deinit-ben, ellenkező esetben crash történik az értesítés küldésekor.
  • NotificationQueue lehetővé teszi az értesítések elhalasztását aszinkron kézbesítéshez.

Mi az a NotificationCenter?

NotificationCenter (NSNotificationCenter) — egy beépített iOS mechanizmus a lazán kapcsolt kommunikáció megvalósításához objektumok között. Az Observer minta lehetővé teszi egy objektum (feladó) számára, hogy közvetlen hivatkozás nélkül értesítsen több más objektumot (megfigyelőt) egy esemény bekövetkeztéről. A NotificationCenter három entitással működik: Notification.Name (értesítés azonosítója), Notification (adatokat tartalmazó konténer) és NotificationCenter (diszpécser). Minden alkalmazás rendelkezik egy megosztott default center-rel.

NSNotification és Notification.Name

Notification.Name — egy struktúra, amely azonosítja az értesítés típusát. Az extension Name: Notification.Name("MyNotification") segítségével hozható létre. A Notification — egy objektum, amely name, object (feladó) és userInfo (adatokat tartalmazó szótár) elemeket tartalmaz. A rendszerértesítések konstansként vannak deklarálva: UIApplication.didBecomeActiveNotification, UIResponder.keyboardWillShowNotification. Az egyéni értesítéseket extension segítségével kell csoportosítani a névütközések elkerülése érdekében. A neveknek fordított-domainnek kell lenniük.

swift
// Egyéni értesítések meghatározása
extension Notification.Name {
    static let dataDidUpdate =
        Notification.Name("com.app.dataDidUpdate")
    static let userLoggedOut =
        Notification.Name("com.app.userLoggedOut")
}

// Értesítés küldése adatokkal
let userInfo: [String: Any] = [
    "userId": 123,
    "timestamp": Date()
]
NotificationCenter.default.post(
    name: .dataDidUpdate,
    object: nil,
    userInfo: userInfo
)

Megfigyelő hozzáadása (addObserver)

A megfigyelő az addObserver(_:selector:name:object:) metódussal iratkozik fel egy értesítésre. Selector — a metódus, amely az értesítés vételekor kerül meghívásra. Az object paraméter lehetővé teszi az értesítések szűrését egy adott feladótól. Ha az object nil, a megfigyelő minden értesítést megkap a megadott névvel bármely feladótól. iOS 9-től kezdve az addObserver nem igényel kézi eltávolítást a block-based API esetében, de a selector-based még mindig removeObserver-t igényel.

swift
// Feliratkozás értesítésre (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)
}

// Feliratkozás értesítésre (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)
}

Hogyan működik a NotificationCenter?

A NotificationCenter egy leképezési táblát tárol (name → megfigyelők halmaza). Amikor a feladó meghívja a post(name:object:)-t, az értesítési központ szinkron módon bejárja az összes, erre a névre feliratkozott megfigyelőt, és meghívja azok szelektorait vagy blokkjait. Kulcsfontosságú jellemző: a post blokkolja az aktuális szálat az összes handler befejezéséig. Ha a handlerek nehéz műveleteket hajtanak végre, ez késlelteti a feladót. A NotificationQueue ezt a problémát oldja meg az értesítések kézbesítésének késleltetésével.

Szinkron küldés (post)

A post(name:object:userInfo:) metódus azonnal elküldi az értesítést az összes megfigyelőnek. A hívás szinkron — a post utáni kód csak az összes handler befejeződése után hajtódik végre. A megfigyelők hívási sorrendje nincs garantálva, és a futtatások között változhat. Szekvenciális feldolgozáshoz használja a NotificationQueue-t coalescing-gal. Ne hívja a post-ot ugyanazon értesítés handlerén belül — ez végtelen rekurzióhoz vezet.

Késleltetett küldés (NotificationQueue)

NotificationQueue értesítéseket ad egy sorhoz aszinkron kézbesítés céljából. Támogatja a coalescing-ot (azonos értesítések összevonása) és a kézbesítési sor kiválasztását (asap, idle, modal). A coalescing hasznos gyakori eseményeknél (betöltési előrehaladás), amikor csak az utolsó értékkel kell értesíteni. A NotificationQueue a run loop-ot használja az aktiváláshoz, ezért csak aktív run loop-pal rendelkező szálakon működik.

swift
// Késleltetett küldés NotificationQueue segítségével
let notification = Notification(
    name: .dataDidUpdate,
    object: self,
    userInfo: ["progress": 0.5]
)

// Coalescing: több értesítés összevonása egybe
NotificationQueue.default.enqueue(
    notification,
    postingStyle: .whenIdle,
    coalesceMask: .onName,
    forModes: [.common]
)

// Aszinkron küldés DispatchQueue segítségével
DispatchQueue.main.async {
    NotificationCenter.default.post(name: .dataDidUpdate, object: nil)
}

Notification vs Delegate vs KVO

Az iOS három fő kommunikációs mechanizmust kínál objektumok között: NotificationCenter, Delegate és KVO (Key-Value Observing). Mindegyik megoldja az értesítési problémát, de különböző kompromisszumokkal a kapcsoltság, a teljesítmény és a típusbiztonság tekintetében. A mechanizmus kiválasztása az „egy-az-egyhez" vagy „egy-a-többhöz" kapcsolattól és az adatátviteli igénytől függ.

JellemzőNotificationCenterDelegateKVO
KapcsoltságGyenge (értesítés neve)Erős (protokoll)Közepes (kulcs)
KapcsolatEgy-a-többhözEgy-az-egyhezEgy-a-többhöz
TípusbiztonságAlacsony (userInfo Dictionary-ként)Magas (protokoll metódusai)Közepes (Any?)
TeljesítményKözepes (tábla bejárása)Magas (közvetlen hívás)Alacsony (NSObject)
AszinkronitásSzinkron (post blokkol)Szinkron a feladó szálábanSzinkron változáskor

Mikor válassza a NotificationCenter-t

A NotificationCenter ideális olyan eseményekhez, amelyekre több független komponensnek kell reagálnia. Példák: alkalmazásbeállítások módosítása, felhasználó kijelentkezése, push értesítés fogadása a háttérben. A NotificationCenter alkalmas lazán kapcsolt modulokhoz is (A funkciónak nem kell tudnia B funkcióról). Hátrány — nincs típusbiztonság: a userInfo kulcsok sztringek, nem enumok.

Mikor válassza a Delegate-et vagy KVO-t

Delegate-et válasszon egy-az-egyhez kapcsolathoz egyértelmű szerződéssel (tableView.delegate). A Delegate gyorsabb és típusbiztonságosabb. KVO-t válasszon egy modell egy adott tulajdonságának változásának megfigyeléséhez (isLoading, progress). A KVO az NSObject-től való öröklődést igényel, és nehézségeket okozhat a hibakeresésben (varázslatos kulcssztringek). A modern Swift-ben a Combine és az async sequences mindhárom megközelítést helyettesíti.

AddObserver: szinkron és aszinkron értesítések

Az addObserver metódus két feliratkozási változatot támogat: selector-based (hagyományos) és block-based (lezárással). Selector-based @objc kompatibilitást és a megfigyelő kézi eltávolítását igényli. Block-based (iOS 9+) lehetővé teszi a capture lista használatát, és automatikusan kezeli az OS, ha erős referenciák nélküli blokkokat használ. A block-based támogatja a queue-t is — a megfigyelő a megadott sorban kapja az értesítést.

Selector-based addObserver

A feliratkozás hagyományos módja szelektor segítségével. A handler metódust @objc-vel kell megjelölni, és opcionális Notification-t kell fogadnia. Előny: bármely osztály használhatja, beleértve a legacy Objective-C-t is. Hátrányok: a szelektor típusbiztonságának hiánya, elírás kockázata a szelektor nevében, kötelező removeObserver a deinit-ben. Ha a megfigyelőt az objektum előtt távolítják el, a handler nem hívódik meg.

Block-based addObserver

A block-based API egy lezárást fogad, amely az értesítés vételekor hajtódik végre. A queue paraméter határozza meg, hogy a blokk melyik sorban hajtódjon végre — main queue az UI-frissítésekhez vagy background queue az adatfeldolgozáshoz. A visszaadott NSObjectProtocol érték a megfigyelő eltávolítására szolgál: NotificationCenter.default.removeObserver(observer). A block-based előnyben részesítendő a modern Swift-ben.

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

// Használat automatikus eltávolítással
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() }
    }
}

Memóriakezelés és megfigyelők eltávolítása

Memóriaszivárgás — az egyik fő probléma a NotificationCenter-rel való munka során. Ha a megfigyelőt nem távolítják el a felszabadítás előtt, az értesítés küldésekor a központ megpróbálja meghívni a már felszabadított objektum metódusát, ami EXC_BAD_ACCESS-hez vezet. iOS 9-től kezdve a block-based addObserver gyenge referenciákat használ, de a selector-based még mindig kézi removeObserver-t igényel. Best practice: távolítsa el a megfigyelőt a deinit-ben.

Mikor hívja a removeObserver-t

Selector-based: kötelezően hívja meg a NotificationCenter.default.removeObserver(self)-t a deinit-ben. Ha a megfigyelő több értesítésre van feliratkozva, mindegyik egyszerre eltávolítható (paraméterek nélkül) vagy egy adott név alapján. Block-based: távolítsa el a removeObserver segítségével az addObserver-től kapott token segítségével. A block-based esetében iOS 9+ rendszeren nincs szivárgás, de az eltávolítás továbbra is ajánlott a teljesítmény érdekében: a felszabadított megfigyelők nem lesznek bejárva a post során.

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

Gyenge referenciák a Token minta segítségével

A Token minta automatizálja a megfigyelők kezelését. Feliratkozáskor egy token-objektum (NSObjectProtocol) kerül visszaadásra, amely a felszabadításkor automatikusan eltávolítja a megfigyelőt. NotificationTokenWrapper gyenge referenciát tárol a NotificationCenter-re és a megfigyelő tokenre, meghívva a removeObserver-t a deinit-ben. Ez közelebb hozza a NotificationCenter-t a Combine megközelítéshez, ahol az AnyCancellable kezeli a feliratkozás életciklusát.

NotificationCenter több szálas környezetben

Thread safety A NotificationCenter garantálja, hogy a post bármely szálból meghívható, és minden megfigyelő ugyanabban a szálban kapja az értesítést, ahol a post-ot meghívták. Ez kritikus a több szálas alkalmazásoknál: ha az értesítést egy háttérszálból küldték, a handlerek is a háttérszálban hajtódnak végre. Az UI frissítéséhez a feldolgozást a main queue-ba kell diszponálni a DispatchQueue.main.async segítségével.

A post és addObserver szálbiztonsága

A NotificationCenter szálbiztos a post és addObserver hívásokhoz különböző szálakból. Belső szinkronizáció zárolást használ, ezért a gyakori post több szálból contention-t okozhat. Nagy terhelésű forgatókönyvekhez (1000 fájl betöltési állapota) használjon külön értesítési sort vagy Combine publisher-t. A NotificationQueue postingStyle .now értékkel egyenértékű a közvetlen post-tal.

Aszinkron kézbesítés Combine segítségével

A NotificationCenter támogatja a Combine publisher-t a NotificationCenter.default.publisher(for:object:) segítségével. Publisher minden értesítést Combine eseménnyé alakít, amely map, filter, debounce és throttle segítségével transzformálható. Ez megoldja a szinkron kézbesítés problémáját: a Combine aszinkron módon dolgozza fel az értesítéseket a megadott Scheduler-en. A NotificationCenter.publisher — híd a legacy mechanizmus és a modern reaktív programozás között.

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

Gyakran ismételt kérdések

Szálbiztos a NotificationCenter?

Igen, a NotificationCenter szálbiztos a post és addObserver hívásokhoz bármely szálból. Azonban a handlerek ugyanabban a szálban hajtódnak végre, ahol a post-ot meghívták. Az UI frissítéséhez használja a queue: .main-t a block-based addObserver-ben vagy a DispatchQueue.main.async-t a handleren belül. A Combine publisher a receive(on:)-nel szintén megoldja a szálproblémát.

Mi történik, ha nem távolítja el a megfigyelőt?

Selector-based: crash EXC_BAD_ACCESS az értesítés küldésekor a megfigyelő felszabadítása után. Block-based (iOS 9+): nincs szivárgás a gyenge referenciának köszönhetően, de az értesítési központ továbbra is memóriában tartja a blokkot az explicit removeObserver-ig. Ajánlott mindig eltávolítani a megfigyelőt a deinit-ben, vagy a Token mintát használni az automatikus kezeléshez.

Mi a különbség a NotificationCenter és a KVO között?

NotificationCenter — tetszőleges események szórása nem kapcsolódó komponensek között. KVO — egy adott objektum adott tulajdonságának változásának megfigyelése. A KVO az NSObject-től való öröklődést igényel, és automatikusan értesít a tulajdonság setteren keresztüli változásakor. A NotificationCenter csak explicit post híváskor értesít. Modell megfigyeléséhez a KVO vagy a Combine előnyösebb.

Hány NotificationCenter létezik egy alkalmazásban?

Egy default center alkalmazásfolyamatonként. További központok hozhatók létre a NotificationCenter() segítségével, de a gyakorlatban a megosztott default-ot használják. Minden központ függetlenül működik — az egyikben történő post nem kerül kézbesítésre a másik megfigyelőinek. A modulok elkülönítéséhez használjon külön Name névtereket fordított-domain értesítési nevekkel.

Helyettesíti a Combine a NotificationCenter-t?

Részben. A Combine NotificationCenter.Publisher-t biztosít, amely a NotificationCenter-t egy reaktív folyamba csomagolja. A Combine megoldja a szinkronitás problémáját (a receive(on:) segítségével), transzformációs operátorokat és automatikus feliratkozás-kezelést (AnyCancellable) ad hozzá. Azonban a NotificationCenter továbbra is megmarad az iOS rendszerértesítéseihez (UIApplication, UIKeyboard) és a legacy kódhoz. A Combine egy kiegészítő réteg, nem helyettesítés.

Összefoglalás

  • NotificationCenter — az Observer minta megvalósítása a lazán kapcsolt „egy-a-többhöz" kommunikációhoz iOS-ben.
  • post szinkron módon küldi el az értesítést az összes megfigyelőnek az aktuális szálban, blokkolva a feladót.
  • addObserver támogatja a selector-based (with @objc) és a block-based (capture list és queue) feliratkozást.
  • removeObserver kötelező a deinit-ben a selector-based feliratkozásoknál, különben crash.
  • NotificationQueue késleltetett kézbesítést biztosít coalescing-gal gyakori eseményekhez.
  • Thread safety garantálja a működést bármely szálból, de a handlerek a feladó szálában hajtódnak végre.
  • Használja a Token mintát vagy a Combine publisher-t a biztonságos és modern feliratkozás-kezeléshez.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is