You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何避免重复添加NotificationCenter观察者?

Swift 避免重复添加 NotificationCenter 观察者的解决方案

你遇到的问题是因为重复添加了完全相同的观察者(同一对象、同一selector、同一通知名、同一object),导致通知触发时回调函数被多次执行。以下是几种可靠的解决方法:

方法1:添加前先移除对应观察者

NotificationCenter 的 removeObserver 方法即使在没有对应观察者的情况下调用也不会崩溃,所以可以直接在添加前先移除,确保只会存在一个观察者实例:

let notificationName = NSNotification.Name(rawValue: "SameObserver")
// 先移除已存在的对应观察者
NotificationCenter.default.removeObserver(self, name: notificationName, object: nil)
// 再添加新的观察者
NotificationCenter.default.addObserver(self, selector: #selector(myFunction(notification:)), name: notificationName, object: nil)

注意:removeObserver 的参数要和 addObserver 完全匹配,这样才能精准移除目标观察者。

方法2:使用Block式观察者并保存引用

如果使用Block方式添加观察者,NotificationCenter 会返回一个 NSObjectProtocol 类型的观察者对象,我们可以将其保存在实例变量中,添加前检查是否已存在:

// 定义实例变量存储观察者引用
private var myNotificationObserver: NSObjectProtocol?

func setupNotificationObserver() {
    // 如果观察者已存在,直接返回不重复添加
    guard myNotificationObserver == nil else { return }
    
    let notificationName = NSNotification.Name(rawValue: "SameObserver")
    myNotificationObserver = NotificationCenter.default.addObserver(
        forName: notificationName,
        object: nil,
        queue: .main
    ) { [weak self] notification in
        self?.myFunction(notification: notification)
    }
}

// 记得在对象销毁时移除观察者
deinit {
    if let observer = myNotificationObserver {
        NotificationCenter.default.removeObserver(observer)
    }
}

@objc func myFunction(notification: Notification) {
    // 你的业务逻辑
}

这种方式需要注意用 [weak self] 避免循环引用,同时在 deinit 中手动移除观察者,防止内存泄漏。

方法3:通过Runtime检查观察者(不推荐生产环境)

NotificationCenter 没有公开API让我们直接查询已添加的观察者,不过可以通过Runtime访问其私有属性来实现检查。但这种方法依赖苹果的内部实现,可能在iOS版本更新后失效,仅作参考:

import ObjectiveC

extension NotificationCenter {
    func hasExistingObserver(for target: Any, name: NSNotification.Name?, object: Any?, selector: Selector) -> Bool {
        guard let observers = self.value(forKey: "_observers") as? [AnyObject] else { return false }
        
        for observer in observers {
            let observerTarget = observer.value(forKey: "_observer") as? NSObject
            let observerSelector = observer.value(forKey: "_selector") as? Selector
            let observerName = observer.value(forKey: "_name") as? NSNotification.Name
            let observerObject = observer.value(forKey: "_object")
            
            if observerTarget === target as? NSObject,
               observerSelector == selector,
               observerName == name,
               observerObject === object {
                return true
            }
        }
        return false
    }
}

使用示例:

let notificationName = NSNotification.Name(rawValue: "SameObserver")
let targetSelector = #selector(myFunction(notification:))

if !NotificationCenter.default.hasExistingObserver(for: self, name: notificationName, object: nil, selector: targetSelector) {
    NotificationCenter.default.addObserver(self, selector: targetSelector, name: notificationName, object: nil)
}

总结

优先推荐方法1和方法2,这两种方法简单可靠,没有私有API的风险,能有效避免重复添加观察者导致的多次回调问题。

内容的提问来源于stack exchange,提问作者Antonio Labra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:16:21