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

SwiftUI接收推送通知时如何实现指定列表每次刷新?

解决SwiftUI推送通知触发列表刷新问题

核心问题分析

  1. 之前用ObservedObject导致列表反复刷新,是因为ObservedObject在视图重建时会重新初始化,触发不必要的状态更新;改用StateObject后只初始化一次是正确的,但当前仅能刷新一次,主要原因是:
    • fetchAllUsers方法每次调用都是追加数据,没有清空旧列表,导致数组元素重复,ForEach无法感知到有效更新
    • 推送通知的回调没有正确绑定到ViewModel的数据刷新逻辑

分步解决方案

1. 修复ViewModel的fetch方法

修改MapViewModel的fetchAllUsers,每次请求前清空旧数据,确保每次都是最新的用户列表:

class MapViewModel: ObservableObject {
    @Published var users = [ChatUsers]()
    
    func fetchAllUsers() {
        // 先清空旧数据,避免重复添加
        users.removeAll()
        FirebaseManager.shared.fireStore.collection("users")
            .getDocuments { documentSnapshot, error in
                if let error = error {
                    print("Failed to fetch users : ", error)
                    return
                }

                documentSnapshot?.documents.forEach { snapshot in
                    let data = snapshot.data()
                    self.users.append(.init(data: data))
                }
            }
    }
}

2. 配置推送通知回调

在App的生命周期中设置通知代理,收到推送时通过NotificationCenter发送刷新信号:

@main
struct YourApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            MapviewUI()
        }
    }
}

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 请求通知权限
        UNUserNotificationCenter.current().delegate = self
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
        )
        application.registerForRemoteNotifications()
        return true
    }
    
    // 前台收到通知时触发
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        NotificationCenter.default.post(name: NSNotification.Name("RefreshMapUsers"), object: nil)
        completionHandler([.banner, .sound])
    }
    
    // 点击通知时触发
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        NotificationCenter.default.post(name: NSNotification.Name("RefreshMapUsers"), object: nil)
        completionHandler()
    }
}

3. 在视图中监听刷新信号

修改MapviewUI,监听通知信号并触发ViewModel的刷新,同时确保数据模型遵循Identifiable:

// 确保ChatUsers遵循Identifiable协议
struct ChatUsers: Identifiable {
    let id: String
    let email: String
    // 其他属性
    
    init(data: [String: Any]) {
        self.id = data["uid"] as? String ?? UUID().uuidString
        self.email = data["email"] as? String ?? ""
        // 初始化其他属性
    }
}

struct MapviewUI: View {
    @StateObject var viewModel = SettingsViewModel()
    @StateObject var vm = MapViewModel()
    @State private var pushNotificationReceived = false
    
    var body: some View {
        VStack {
            if !pushNotificationReceived {
                ForEach(viewModel.users) { user in
                    NavigationLink(destination: ChatSwiftUIView(chatUser: user)) {
                        VStack(alignment: .leading) {
                            Text(user.email)
                                .multilineTextAlignment(.leading)
                        }
                    }
                    .padding(.horizontal)
                    .padding(.top, 8)
                }
            } else {
                ForEach(vm.users) { user in
                    NavigationLink(destination: ChatSwiftUIView(chatUser: user)) {
                        VStack(alignment: .leading) {
                            Text(user.email)
                                .multilineTextAlignment(.leading)
                        }
                    }
                    .padding(.horizontal)
                    .padding(.top, 8)
                }
            }
        }
        .onAppear {
            // 初始加载数据
            viewModel.fetchAllUsers()
            vm.fetchAllUsers()
        }
        .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("RefreshMapUsers"))) { _ in
            // 每次收到通知,刷新MapViewModel的用户列表
            vm.fetchAllUsers()
            pushNotificationReceived = true
        }
    }
}

关键注意点

  • 始终用StateObject持有ViewModel,确保其生命周期与视图一致,避免重复初始化
  • 数据模型必须遵循Identifiable(或在ForEach中指定id参数),否则ForEach无法正确识别元素变化
  • 推送通知的回调逻辑要确保能触发ViewModel的刷新方法,通过NotificationCenter是SwiftUI中跨组件传递事件的常用方式

内容的提问来源于stack exchange,提问作者Swati Dasgupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 11:33:26