iOS/Swift应用CFNotificationCenter屏幕状态事件重复触发问题求助
嘿,我来帮你排查这个屏幕亮灭事件重复触发的问题~ 从你描述的现象(每次循环触发次数递增)来看,最可能的原因是观察者被重复注册了,再结合Darwin通知的特性,咱们一步步来解决:
一、优先排查:观察者是否被多次添加
你这段添加CFNotificationCenterAddObserver的代码,如果是放在applicationDidBecomeActive这类会被多次调用的方法里,每次App从后台回到前台,就会重复注册一次观察者——每多注册一次,同一通知就会多触发一次回调。
解决方法:
给AppDelegate加个标记位,确保观察者只被添加一次:
private var hasRegisteredDisplayObserver = false func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 只在App启动时注册一次观察者 if !hasRegisteredDisplayObserver { CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), Unmanaged.passUnretained(self).toOpaque(), displayStatusChangedCallback, "com.apple.springboard.hasBlankedScreen" as CFString, nil, .deliverImmediately) // 别忘了注册解锁的通知,用来重置状态 CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), Unmanaged.passUnretained(self).toOpaque(), displayStatusChangedCallback, "com.apple.springboard.unlockComplete" as CFString, nil, .deliverImmediately) hasRegisteredDisplayObserver = true } return true }
二、添加状态锁,过滤重复通知
有些SpringBoard的通知(比如hasBlankedScreen)可能在系统内部会被多次发送,或者同一状态下重复触发。这时候可以加个状态变量,只在状态变化时执行记录逻辑:
private var isScreenBlanked = false private func displayStatusChanged(_ lockState: String) { print("Darwin notification NAME = \(lockState)") if lockState == "com.apple.springboard.hasBlankedScreen" { // 如果已经是锁屏状态,直接跳过重复通知 guard !isScreenBlanked else { return } isScreenBlanked = true print("A single Blank Screen") let statusString = dbSource() statusString.infoString = "blanked screen" print("statusString: \(statusString)") statusString.save() } else if lockState == "com.apple.springboard.unlockComplete" { // 解锁时重置状态,避免下次锁屏被过滤 guard isScreenBlanked else { return } isScreenBlanked = false // 这里可以添加解锁事件的记录逻辑(如果需要的话) let statusString = dbSource() statusString.infoString = "unlocked screen" statusString.save() } }
三、别忘了移除观察者(避免内存问题)
在AppDelegate销毁时,记得移除注册的观察者,防止内存泄漏:
deinit { CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), Unmanaged.passUnretained(self).toOpaque(), "com.apple.springboard.hasBlankedScreen" as CFString, nil) CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), Unmanaged.passUnretained(self).toOpaque(), "com.apple.springboard.unlockComplete" as CFString, nil) }
排查步骤总结
- 先确认添加观察者的代码只执行了一次(检查调用时机,加标记位)
- 用状态变量过滤同一状态下的重复通知
- 配对监听锁屏/解锁通知,保证状态正确切换
- 销毁时移除观察者,避免潜在问题
内容的提问来源于stack exchange,提问作者RLW
相关产品推荐
相关产品推荐

