SwiftUI中无法将AppDelegate本地通知信息传递至视图
问题:本地通知信息无法传递到SwiftUI的MainView
已配置好可正常触发的本地通知,想要从中提取信息并跳转至指定视图,但目前无法将通知信息传递到MainView的onReceive代码块中。能在AppDelegate的代码中看到通知内容,推测遗漏了关键步骤,核心需求是将AppDelegate中的通知信息传递到MainView。
原代码
@main struct UntitledNewsApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @StateObject var notificationData = NotificationData() var body: some Scene { WindowGroup { MainView() .environmentObject(notificationData) } } } class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { var notificationData = NotificationData() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { UNUserNotificationCenter.current().delegate = self return true } func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { // Handle the received notification and navigate to the desired view if response.actionIdentifier == UNNotificationDefaultActionIdentifier { let articleResponse = response.notification.request.content notificationData.notificationTitle = articleResponse.title DispatchQueue.main.async { if let appDelegate = UIApplication.shared.delegate as? AppDelegate { appDelegate.notificationData.notificationTitle = articleResponse.title } } // Notification tapped, navigate to the desired view NotificationCenter.default.post(name: NSNotification.Name("NotificationTapped"), object: nil) } completionHandler() } } class NotificationData: ObservableObject { @Published var notificationTitle: String = "" } struct MainView: View { @EnvironmentObject var notificationData: NotificationData // ... 其他代码 var body: some View { Text("Never Give You Up") .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("NotificationTapped"))) { notification in print("onReceive in blank: \(notificationData.notificationTitle)") } } }
问题根源
你在AppDelegate中创建了一个独立的NotificationData实例,而MainView使用的是App中@StateObject创建的另一个实例——两者是完全独立的对象,因此AppDelegate中修改的通知信息无法同步到MainView的环境对象中。
修复方案
修改核心点
- 移除AppDelegate中私有的
NotificationData实例,改为引用App中共享的实例 - 在App启动时,让AppDelegate获取到App中的
notificationData - 确保在主线程更新ObservableObject数据(通知回调可能在后台线程执行)
- 先更新数据再发送通知,保证
onReceive触发时数据已同步
修改后的完整代码
@main struct UntitledNewsApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @StateObject var notificationData = NotificationData() var body: some Scene { WindowGroup { MainView() .environmentObject(notificationData) } } } class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { // 改为引用共享的NotificationData实例 private var sharedNotificationData: NotificationData? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { UNUserNotificationCenter.current().delegate = self // 获取App中共享的NotificationData实例 if let app = application.delegate as? UntitledNewsApp { sharedNotificationData = app.notificationData } return true } func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { guard response.actionIdentifier == UNNotificationDefaultActionIdentifier else { completionHandler() return } let articleResponse = response.notification.request.content // 在主线程更新共享数据,再发送通知 DispatchQueue.main.async { self.sharedNotificationData?.notificationTitle = articleResponse.title NotificationCenter.default.post(name: NSNotification.Name("NotificationTapped"), object: nil) } completionHandler() } } class NotificationData: ObservableObject { @Published var notificationTitle: String = "" } struct MainView: View { @EnvironmentObject var notificationData: NotificationData // ... 其他代码 var body: some View { Text("Never Give You Up") .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("NotificationTapped"))) { _ in print("onReceive in blank: \(notificationData.notificationTitle)") } } }
额外优化建议
- 可以给通知名称定义一个全局常量,避免硬编码字符串:
使用时直接写extension Notification.Name { static let notificationTapped = Notification.Name("NotificationTapped") }.notificationTapped即可。 - 如果只需要通过
@Published属性的变化来触发视图更新,甚至可以去掉NotificationCenter的使用,直接在MainView中监听notificationTitle的变化:.onChange(of: notificationData.notificationTitle) { newTitle in if !newTitle.isEmpty { print("Notification title updated: \(newTitle)") // 这里执行跳转逻辑 } }
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

