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

SwiftUI中Firestore无法实时更新聊天消息问题求助

SwiftUI + Firestore 聊天消息无法实时更新问题

我在SwiftUI中通过Firestore获取聊天消息,发送或接收新消息后,必须重新加载ChatScreen才能看到更新。

试过两种方案:

  • 用Realtime Database实现时,实时更新正常,但分页实现难度大且成本较高
  • 将ChatViewModel的@StateObject替换为@ObservedObject后,消息会在几秒后从滚动栏中消失

ChatViewModel 代码

class ChatViewModel: ObservableObject {
    @Published var messages: [Message] = []
    let databaseRef = Database.database().reference()
    @Published var usersList: [userInfo] = []
    
    
    func sendMessage(messageText: String, userId: String, userName: String, groupId: String) {
        let db = Firestore.firestore()
        let messageData: [String: Any] = [
            "text": messageText,
            "userId": userId,
            "groupId": groupId,
            "userName": userName,
            "timestamp": Date().timeIntervalSince1970 * 1000
        ]

        db.collection("groups")
            .document(groupId)
            .collection("messages")
            .addDocument(data: messageData) { error in
                if let error = error {
                    print("Error adding message: \(error.localizedDescription)")
                } else {
                }
            }
    }

    func observeMessages(groupId: String) {
        let db = Firestore.firestore()
        let messagesRef = 
    db.collection("groups").document(groupId).collection("messages").order(by: 
    "timestamp", descending: true).limit(to: 25)
        
        messagesRef.addSnapshotListener{ querySnapshot, error in
            if let error = error {
                print(error)
            }
            
            DispatchQueue.main.async {
                querySnapshot?.documentChanges.forEach({ change in
                    if change.type == .added {
                        let data = change.document.data()
                        self.messages.append(.init(documentId: change.document.documentID, data: data))
                    }
                })
            }
        }
    }
}

ChatScreen 代码

struct ChatScreen: View {
    @State private var message = ""
    var group: ChatGroup
    var userId: String
    @StateObject var chatViewModel = ChatViewModel()
    let db = Database.database().reference()
    @State private var goToUserListScreen = false
    
    init(group: ChatGroup, userId: String) {
        self.group = group
        self.userId = userId
    }
    
    var body: some View {
        ZStack{
            VStack {
                ScrollView(.vertical, showsIndicators: true, content:{
                    LazyVStack{
                        ForEach(chatViewModel.messages) { message in
                            MessageView(message: message, userId: userId).rotationEffect(Angle(degrees: 180)).scaleEffect(x: -1.0, y: 1.0, anchor: .center)
                        }
                        .padding(.horizontal)
                        HStack{Spacer()}
                    }
                })
                .onAppear(){
                    chatViewModel.observeMessages(groupId: group.id)
                }
                .background(.opacity(0.05))
                .frame(maxWidth: .infinity)
                .rotationEffect(Angle(degrees: 180)).scaleEffect(x: -1.0, y: 1.0, anchor: .center)
                .scrollDismissesKeyboard(.interactively)
                .toolbar(content: {
                                ToolbarItem(placement: .principal) {
                                    Text(group.groupName)
                                        .bold()
                                        .onTapGesture {
                                            self.goToUserListScreen = true
                                        }
                                }
                            })
                .navigationBarTitleDisplayMode(.inline)
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Text("Test")
                    }
                    
                }
                HStack {
                    TextField("Type your message here", text: $message)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .controlSize(.large)
                    Button {
                        chatViewModel.sendMessage(messageText: message, userId: userId, userName: "Test", groupId: group.id)
                        message = ""
                    } label: {
                        Image(systemName: "arrow.up.circle.fill")
                            .foregroundStyle(message.isEmpty ? .gray : .blue)
                            .font(.system(size: 30))
                    }
                    .disabled(message.isEmpty)
                }
                .padding(.horizontal)
                .padding(.bottom, 7)
                .padding(.top, 1)
            }
            .navigationDestination(isPresented: $goToUserListScreen){
                UserListScreen(group: group)
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Deepanshu Kashyap

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 13:45:12