大项目中User notifications的Closure块未执行,getNotificationSettings闭包被跳过
排查大项目中
UNUserNotificationCenter.getNotificationSettings回调不执行的问题 碰到这种小项目正常跑、大项目直接跳过completion handler的问题真的很闹心,我结合实际开发经验给你梳理几个最可能的原因和排查方向:
可能的核心原因
UNUserNotificationCenter实例生命周期问题:如果你的代码里是用局部变量创建的通知中心实例(哪怕用了current()但被意外释放),大项目里复杂的内存环境可能导致实例在回调触发前就被销毁了,自然不会执行block里的逻辑。小项目里变量生命周期长,这个问题不容易暴露。- 主线程阻塞/死锁:
getNotificationSettings的completion handler默认会回到调用它的队列(如果是主队列的话),如果大项目里主线程被同步阻塞的耗时操作、死锁卡住了,回调就没法及时执行甚至完全被跳过。 - 竞态条件与第三方库冲突:大项目里可能有其他模块、第三方库在同时操作通知权限(比如提前请求授权、修改设置),导致系统的通知设置回调触发逻辑被干扰,出现竞态条件。
- 调用时机过早:如果在
UIApplicationDidFinishLaunching之前就调用getNotificationSettings,系统的通知中心可能还没完成初始化,导致回调无法正常触发。
分步排查方案
- 强引用通知中心实例:把
UNUserNotificationCenter.current()的引用存为类的属性(而不是局部变量),确保在回调执行前实例不会被释放。比如封装一个单例的通知管理类,持有center的强引用。 - 检查主线程状态:用Xcode的Debug Navigator查看主线程的调用栈,看看有没有长时间阻塞的任务、死锁情况(比如有没有同步调用主队列的代码导致死锁)。
- 简化回调代码:先把回调里的逻辑简化到只打印日志,排除是不是block内部的代码(比如UI操作崩溃、逻辑错误)导致的“看似跳过”(其实是崩溃被异常捕获机制吞了)。
- 确认调用时机:确保
getNotificationSettings是在App完全启动后调用的(比如在viewDidAppear里测试,而不是在启动初期)。 - 排查第三方库干扰:临时移除项目里和通知权限相关的第三方库,测试回调是否正常执行,定位是不是第三方库的冲突。
正确示例代码
// 封装一个单例通知管理类,确保center的强引用 class NotificationManager { static let shared = NotificationManager() private let center = UNUserNotificationCenter.current() private init() {} func checkNotificationPermissions() { center.getNotificationSettings { settings in // 先打印基础日志,确认回调是否触发 print("Received notification settings: \(settings.authorizationStatus.rawValue)") // 你的业务逻辑 switch settings.authorizationStatus { case .authorized: print("已授权通知权限") // 执行后续操作 case .denied: print("通知权限被拒绝") // 引导用户开启权限 case .notDetermined: print("未请求通知权限") // 发起权限请求 default: break } } } } // 调用方式 NotificationManager.shared.checkNotificationPermissions()
内容的提问来源于stack exchange,提问作者Jordan Heath
相关产品推荐
相关产品推荐

