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

iOS 本地通知回调时自定义协议delegate已设置却仍为nil

问题核心成因

出现delegate莫名为nil的根本原因是:收到系统通知回调的LocalNotification实例,和你之前赋值过delegate的实例,根本不是同一个对象。
具体逻辑链条如下:

  • 你在FinalDecisionViewController的setupNotification方法中,通过localNotification = LocalNotification()创建了实例A,给实例A的delegate属性赋值为当前页面控制器,这一步流程是正常的,所以didSet回调可以正常打印was set。
  • 但你的代码从未将实例A设置为UNUserNotificationCenter的delegate。系统收到通知点击事件时,只会调用它自身持有的LocalNotification实例(大概率是你在AppDelegate或应用启动流程中初始化的全局实例B)的通知回调方法。
  • 实例B从未被设置过NavigationProtocol类型的delegate,属性默认值为nil,自然无法触发对应的协议方法。
  • 你之前通过deinit日志排查时,观察的是被页面持有的实例A的释放状态,只要页面控制器没被弹出,实例A就会一直存活,因此你会误以为收到回调的是同一个实例,完全没意识到实例B的存在。
排查步骤
  • 给所有LocalNotification实例添加内存地址打印:
    • 在设置delegate的位置打印localNotification的内存地址、delegate指向的对象内存地址
    • 在userNotificationCenter(_:didReceive:withCompletionHandler:)回调方法中打印当前self的内存地址
    • 对比两处打印的内存地址,大概率会发现两个值完全不一致。
  • 全局搜索UNUserNotificationCenter.current().delegate的赋值位置,确认系统通知中心实际持有的delegate实例是哪一个,排查是否存在多个LocalNotification实例初始化的逻辑。
解决方法
  • 将LocalNotification改造为单例模式,保证全局只有一个实例,所有通知回调都由该实例统一处理:
    class LocalNotification: NSObject, UNUserNotificationCenterDelegate {
        // 全局单例
        static let shared = LocalNotification()
        
        weak var delegate: NavigationProtocol? {
            didSet {
                print("was set")
            }
        }
        
        private override init() {
            super.init()
            // 初始化时直接将自身设置为通知中心的delegate,避免回调偏移
            UNUserNotificationCenter.current().delegate = self
        }
    
        // 保留原有通知调度、回调方法实现
    }
    
  • 业务页面移除本地实例化LocalNotification的逻辑,直接使用单例完成delegate绑定和通知调度:
    private func setupNotification() {
        // 移除原有本地实例化代码
        LocalNotification.shared.delegate = self
        LocalNotification.shared.scheduleNotification(title: "Loan Approval", message: "Congratulations! Your loan has been approved", type: "Loan Approval")
    }
    
  • 补充生命周期匹配逻辑:由于delegate是weak修饰,在页面控制器的deinit方法中主动将单例的delegate置为nil,避免产生悬空引用。

补充注意点:必须在应用启动流程(如AppDelegate的didFinishLaunchingWithOptions方法)中完成LocalNotification单例的初始化,否则当应用被系统杀死后,收到通知唤起进程时,系统将无法找到对应的通知回调delegate。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 02:54:04