SwiftUI对接Firebase的ChatView消息重复,如何刷新视图清除重复数据?
问题根因
- 你的
addMessagesToConv方法中,临时存储消息的数组mensajesTotal定义在快照监听器回调的外部,每次监听器触发(有新消息更新)时不会清空,会持续累加历史所有消息 - 你在遍历快照文档的for循环内部,每处理一条消息就直接覆盖会话的消息数组,相当于循环执行多少次就赋值多少次,也会导致数据异常重复
修复方案
第一步:修正Firebase快照监听逻辑
把mensajesTotal移到回调内部,遍历完全部文档后再统一更新会话的消息列表,修复后的代码如下:
func addMessagesToConv(conversation: Conversation, index: Int) { let ref = self.db.collection("conversations").document(conversation.id!).collection("messages") .order(by: "date") .addSnapshotListener { querySnapshotmsg, error in if error == nil { // 每次快照更新先初始化空数组,清空上一次的旧数据 var mensajesTotal = [Message]() // 遍历所有消息文档 for msgDoc in querySnapshotmsg!.documents { var m = Message() m.createdBy = msgDoc["created_by"] as? String ?? "" m.date = msgDoc["date"] as? Timestamp ?? Timestamp() m.msg = msgDoc["msg"] as? String ?? "" m.id = msgDoc.documentID mensajesTotal.append(m) } // 遍历完所有消息后,再统一更新会话的消息数组 self.chats[index].messages.removeAll() self.chats[index].messages = mensajesTotal } else { print("error: \(error!.localizedDescription)") } } }
第二步:可选优化(完善滚动逻辑)
你当前的滚动逻辑只在ForEach第一次出现时触发,后续有新消息时不会自动滚动到底部,可以给ScrollView加onChange监听:
ForEach(chat.messages, id: \.id) { message in if user.name == message.createdBy { ChatRow(message: message, isMe: true) } else { ChatRow(message: message, isMe: false) } } .onAppear(perform: {scrollView.scrollTo(chat.messages.count-1)}) // 新增监听:消息数组变化时自动滚动到底部 .onChange(of: chat.messages.count) { _ in scrollView.scrollTo(chat.messages.count-1) }
注意事项
- 要确保
Message结构体的id属性是唯一值,你用Firebase的documentID作为id是符合要求的,ForEach不会因为id重复导致渲染异常 - 页面销毁时记得移除Firebase的快照监听器,避免内存泄漏
内容的提问来源于stack exchange,提问作者Nat Serrano
相关产品推荐
相关产品推荐

