iOS通知中心重复触发问题:多次进入视图后savingAll重复执行
问题原因与解决方案
这个问题的核心是你重复注册了通知观察者,且没有在视图控制器生命周期结束时移除它们,具体逻辑是这样的:
- 首次进入视图时,你调用
NotificationCenter.default.addObserver(...)注册了一个观察者,此时App最小化触发通知,savingAll只会执行1次。 - 当你离开这个视图(比如返回上一页或关闭弹窗),如果没有移除这个观察者,NotificationCenter会一直持有这个视图控制器的引用,导致它无法被销毁。
- 当你再次返回这个视图时,代码又会执行一次
addObserver,此时NotificationCenter里就存在两个指向当前视图控制器的观察者。 - 之后每次触发
AppMinimilised通知,所有注册的观察者都会响应,所以saingAll的执行次数会随着你返回视图的次数递增。
解决方法
1. 在视图销毁时手动移除观察者
在你的视图控制器中添加deinit方法,移除对应的通知观察者,确保视图控制器被销毁时清理掉注册的观察者:
deinit { NotificationCenter.default.removeObserver(self, name: Notification.Name("AppMinimilised"), object: nil) }
这样每次视图控制器被销毁时,都会把自己注册的这个通知观察者移除,从根源避免重复注册。
2. 使用Block式通知注册(推荐)
这种方式会返回一个令牌对象,你可以持有它来管理观察者的生命周期,而且能避免selector方式可能出现的方法匹配问题,同时配合弱引用避免内存泄漏:
// 定义属性持有观察者令牌 private var appMinimisedObserver: NSObjectProtocol? override func viewDidLoad() { super.viewDidLoad() // 注册通知,使用weak self避免强引用循环 appMinimisedObserver = NotificationCenter.default.addObserver(forName: Notification.Name("AppMinimilised"), object: nil, queue: .main) { [weak self] _ in self?.savingAll() } } deinit { // 移除观察者 if let observer = appMinimisedObserver { NotificationCenter.default.removeObserver(observer) } }
当视图控制器被销毁时,deinit会触发并移除对应的观察者,不会留下多余的注册项。
3. 确保只注册一次观察者
如果你的视图控制器是常驻内存的(比如TabBar的子页面),可以把注册代码放在viewDidLoad中(viewDidLoad只会在视图控制器初始化时执行一次),而不是viewWillAppear或viewDidAppear,这样就不会重复注册了。
内容的提问来源于stack exchange,提问作者Damian Talaga




