Swift iOS:如何访问AnyHashable数据并加载到视图
Hey there! 既然你已经能从通知的userInfo里解析出title和body这些数据了,接下来把它们展示到视图上其实很 straightforward,我给你分几种常见场景来讲解:
1. UIKit项目(AppDelegate 处理通知)
如果你是在AppDelegate的userNotificationCenter(_:didReceive:withCompletionHandler:)方法里解析的userInfo,那要把数据传到目标ViewController有几种办法:
直接跳转并传值:
先拿到当前的window根控制器,或者通过导航栈push到目标页面,把解析好的title和body传过去。比如:func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo // 你的解析代码 guard let aps = userInfo[AnyHashable("aps")] as? NSDictionary, let alert = aps["alert"] as? NSDictionary, let body = alert["body"] as? String, let title = alert["title"] as? String else { completionHandler() return } // 获取当前根控制器,假设是UINavigationController guard let navController = UIApplication.shared.windows.first?.rootViewController as? UINavigationController else { completionHandler() return } // 实例化目标ViewController,比如NotificationDetailVC let detailVC = NotificationDetailVC() detailVC.notificationTitle = title detailVC.notificationBody = body // 跳转过去 navController.pushViewController(detailVC, animated: true) completionHandler() }然后在
NotificationDetailVC里,只要在viewDidLoad里把值赋值给对应的UILabel就行:class NotificationDetailVC: UIViewController { var notificationTitle: String? var notificationBody: String? @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var bodyLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() titleLabel.text = notificationTitle bodyLabel.text = notificationBody } }用通知中心传值:
如果不想直接依赖导航栈,也可以用NotificationCenter发送通知,让目标ViewController监听:
在解析完数据后发送:let notificationData = ["title": title, "body": body] NotificationCenter.default.post(name: NSNotification.Name("NotificationReceived"), object: nil, userInfo: notificationData)然后在目标VC的
viewDidLoad里监听:override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(handleNotification(_:)), name: NSNotification.Name("NotificationReceived"), object: nil) } @objc func handleNotification(_ notification: Notification) { guard let data = notification.userInfo as? [String: String], let title = data["title"], let body = data["body"] else { return } titleLabel.text = title bodyLabel.text = body } // 记得deinit里移除监听 deinit { NotificationCenter.default.removeObserver(self) }
2. UIKit项目(SceneDelegate 处理通知)
如果你的项目是用SceneDelegate的(iOS 13+),那处理逻辑类似,只是获取根控制器的方式变了:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo // 解析数据... // 获取当前scene的根控制器 guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = scene.windows.first, let navController = window.rootViewController as? UINavigationController else { completionHandler() return } // 后续跳转传值和上面一样 let detailVC = NotificationDetailVC() detailVC.notificationTitle = title detailVC.notificationBody = body navController.pushViewController(detailVC, animated: true) completionHandler() }
3. SwiftUI项目
如果是SwiftUI项目,你可以用@Published属性结合ObservableObject来传递数据:
首先,创建一个全局的通知管理器:
class NotificationManager: ObservableObject { static let shared = NotificationManager() @Published var receivedNotification: (title: String, body: String)? }
然后在通知处理的地方(比如App.swift里的相关回调或者UNUserNotificationCenterDelegate方法):
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo // 解析数据... NotificationManager.shared.receivedNotification = (title: title, body: body) completionHandler() }
最后在你的SwiftUI视图里监听这个@Published属性:
struct NotificationView: View { @StateObject private var notificationManager = NotificationManager.shared var body: some View { VStack { if let notification = notificationManager.receivedNotification { Text(notification.title) .font(.title) Text(notification.body) .font(.body) .padding() } else { Text("No notification received") } } } }
关键注意事项
- 确保在更新UI的时候是在主队列操作,虽然上面的方法大多已经在主队列,但如果你的解析是异步执行的,记得用
DispatchQueue.main.async包裹UI更新代码:DispatchQueue.main.async { self.titleLabel.text = title self.bodyLabel.text = body } - 如果App在后台被唤醒,要确保视图已经加载完成再赋值,不然可能会出现UI控件为nil的情况,用通知中心或者
ObservableObject的方式会更稳妥。
内容的提问来源于stack exchange,提问作者user9606220

