SwiftUI 如何通过通知交互触发视图局部状态更新
解决方案
核心思路是利用你已经实现的ObservableObject协议的NotificationDelegate类,把计数器存储在该类中用@Published修饰,让视图可以订阅数值变化自动刷新,同时代理内部的回调方法也能直接访问修改该变量。
具体修改步骤
- 删除全局的
var notificationCounter = 0变量 - 在
NotificationDelegate类中添加@Published修饰的计数器属性 - 把视图中
@State修饰的delegate改为@StateObject修饰,保证类实例生命周期稳定 - 视图中直接读取
delegate.notificationCounter展示数值
修改后完整代码
import SwiftUI import UserNotifications struct HomeScreenView: View { // 用@StateObject持有ObservableObject类型的代理实例 @StateObject var delegate = NotificationDelegate() var body: some View { ZStack { Color("Nice Green") .ignoresSafeArea() VStack { Button(action: createNotification) { Text("Notify User") } .onAppear(perform: { // 请求通知权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.badge,.sound]) {(_,_) in } UNUserNotificationCenter.current().delegate = delegate }) // 直接读取代理中的计数器属性 Text("Notification Interactions \(delegate.notificationCounter)") } } } func createNotification() { let content = UNMutableNotificationContent() content.title = "God of Posture" content.subtitle = "Straighten Your Neck" content.categoryIdentifier = "Actions" let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 4, repeats: false) let request = UNNotificationRequest(identifier: "In-App", content: content, trigger: trigger) // 通知交互动作 let close = UNNotificationAction(identifier: "Close", title: "Close", options: .destructive) let okay = UNNotificationAction(identifier: "Okay", title: "Okay", options: .destructive) let category = UNNotificationCategory(identifier: "Actions", actions: [close, okay], intentIdentifiers: [], options: []) UNUserNotificationCenter.current().setNotificationCategories([category]) UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) } struct HomeScreenView_Previews: PreviewProvider { static var previews: some View { ContentView().previewDevice(PreviewDevice(rawValue: "iPhone X")) } } } class NotificationDelegate: NSObject, ObservableObject, UNUserNotificationCenterDelegate { // 用@Published修饰计数器,数值变化时自动通知订阅者刷新UI @Published var notificationCounter = 0 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.badge, .banner, .sound]) } func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { if response.actionIdentifier == "Okay" { // 直接修改当前类中的计数器属性 notificationCounter += 1 print("counter is now \(notificationCounter)") } completionHandler() } }
注意说明
@Published是Combine框架的特性,会在属性变化时自动发出事件,所有订阅了该ObservableObject的视图都会自动刷新对应的UI部分- 对于符合
ObservableObject协议的类实例,iOS14+推荐用@StateObject修饰持有,能保证实例生命周期和视图绑定不会意外重置;如果需要兼容iOS13,可以替换为@ObservedObject,但需要自行保证代理实例的生命周期稳定 @State仅用于修饰值类型(Int、String、Struct等),不能正确持有引用类型的类实例
内容的提问来源于stack exchange,提问作者beginnerprogrammerwoo
相关产品推荐
相关产品推荐

