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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 07:15:03