调用3D Touch快捷操作时NotificationCenter未触发的技术问题
解决3D Touch快捷操作中NotificationCenter通知未生效的问题
咱们来拆解下你遇到的问题:当通过3D Touch快捷操作触发performActionForShortcutItem时,发送的通知没被ViewController接收到,大概率是通知发送时机早于观察者注册时机,或者观察者的注册/移除逻辑有疏漏。
可能的原因&对应解决方案
1. 通知发送时机过早
当用户通过3D Touch快捷方式启动App时,performActionForShortcutItem会在App启动流程的早期被调用——这时候你的ViewController可能还没完成初始化,viewDidLoad甚至还没执行,自然还没注册通知观察者,发出去的通知相当于“喊了一声但没人在听”。
解决办法:
- 要么把通知观察者的注册移到更早的时机,比如ViewController的
init方法里; - 更稳妥的方式是放弃依赖通知,直接在
performActionForShortcutItem中找到对应的ViewController,直接调用方法或者设置属性,这样能精准控制执行时机。
举个直接调用的示例:
// AppDelegate.swift func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { // 假设根控制器是导航控制器,获取对应的ViewController if let nav = window?.rootViewController as? UINavigationController, let mainVC = nav.topViewController as? ViewController { mainVC.handleShortcutAction() // 直接调用ViewController的处理方法 completionHandler(true) } else { completionHandler(false) } } // ViewController.swift func handleShortcutAction() { // 这里写3D Touch快捷操作对应的业务逻辑 print("收到3D Touch快捷操作指令") }
2. 通知观察者注册不完整
如果你坚持要用通知,一定要确保ViewController完整注册了观察者,并且在合适的时机移除(避免内存泄漏)。完整的代码应该是这样:
// ViewController.swift override func viewDidLoad() { super.viewDidLoad() // 注册通知观察者,注意通知名字要和AppDelegate里的完全一致 NotificationCenter.default.addObserver(self, selector: #selector(handleNotification), name: Notification.Name("action"), object: nil) } @objc func handleNotification() { // 这里处理通知触发后的逻辑 print("收到3D Touch快捷操作的通知") } deinit { // 页面销毁时移除观察者,防止内存泄漏 NotificationCenter.default.removeObserver(self) }
划重点:通知的名字
Notification.Name("action")要和AppDelegate里的拼写、大小写完全一致,差一个字符都不行。
3. App后台唤醒的情况
如果App已经在后台,通过3D Touch快捷操作唤醒时,performActionForShortcutItem会被调用,但这时候要确保ViewController的观察者没有被意外移除——比如之前页面销毁时没正确移除,或者重新进入时没重新注册。
额外小建议
通知虽然用起来方便,但在这种需要精准控制执行时机的场景下,直接调用ViewController的方法会更可靠,能避免通知“异步触发”带来的接收不到的问题。
内容的提问来源于stack exchange,提问作者ImanX
相关产品推荐
相关产品推荐

