SwiftUI接收推送通知时如何实现指定列表每次刷新?
解决SwiftUI推送通知触发列表刷新问题
核心问题分析
- 之前用
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
相关产品推荐
相关产品推荐

