Swift聊天应用问题:底部显示最新消息时无法加载更多
问题根源
首次查询用.order(by: TIMESTAMP, descending: false).limit(toLast:5)获取的是最新的5条消息,此时lastDocument是这5条中时间戳最大的(最新的那条)。加载更多时用start(afterDocument: lastDocument),相当于请求时间戳比最新消息还晚的消息,自然查不到任何数据,导致TableView无法填充。
修复方案
要实现「最新消息在底部+加载旧消息正常」,可以通过两种思路调整逻辑:
方案一:基于升序查询直接加载历史消息
核心逻辑
首次加载取最新的5条消息,加载更多时请求比当前数组中最早消息更早的历史消息,并将新消息插入数组头部以保持旧→新的顺序。
修改后代码
func fetchChatMessages() { fetchMoreDocs = true var query: Query! if messages.isEmpty { // 首次加载:获取最新的5条消息(升序取最后5条) query = MESSAGES_COLLECTION.document(currentUID!).collection(user.memberId) .order(by: TIMESTAMP, descending: false) .limit(toLast: 5) } else { // 加载更多:获取比当前最早消息更早的5条 guard let firstMessageDoc = messages.first?.documentSnapshot else { fetchMoreDocs = false return } query = MESSAGES_COLLECTION.document(currentUID!).collection(user.memberId) .order(by: TIMESTAMP, descending: false) .start(beforeDocument: firstMessageDoc) .limit(to: 5) } query.addSnapshotListener { (snapshot, error) in if let error = error { print("Error..\(error.localizedDescription)") self.fetchMoreDocs = false return } else if snapshot!.isEmpty { self.fetchMoreDocs = false return } else { let newMessages = Message.parseData(snapshot: snapshot) // 历史消息插入数组头部,保持旧→新顺序 self.messages.insert(contentsOf: newMessages, at: 0) DispatchQueue.main.async { self.chatRoomTV.reloadData() // 仅首次加载后滚动到底部,加载更多时保留当前滚动位置 if self.messages.count == newMessages.count { self.scrollToBottom() } self.fetchMoreDocs = false } } } }
配套调整
确保Message模型保存Firestore的DocumentSnapshot,用于加载更多时定位:
class Message { var documentSnapshot: DocumentSnapshot? // 其他消息属性(内容、发送者等) static func parseData(snapshot: QuerySnapshot?) -> [Message] { var messages = [Message]() guard let docs = snapshot?.documents else { return messages } for doc in docs { let message = Message() // 解析消息内容、发送者等字段... message.documentSnapshot = doc messages.append(message) } return messages } }
方案二:复用降序查询逻辑,反转数组调整顺序
核心逻辑
用你之前验证过的降序查询加载消息,通过反转数组将消息顺序改为旧→新,让最新消息落在数组最后(对应TableView底部)。
修改后代码
func fetchChatMessages() { fetchMoreDocs = true var query: Query! if messages.isEmpty { query = MESSAGES_COLLECTION.document(currentUID!).collection(user.memberId) .order(by: TIMESTAMP, descending: true) .limit(to: 5) } else { guard let lastMessageDoc = messages.last?.documentSnapshot else { fetchMoreDocs = false return } query = MESSAGES_COLLECTION.document(currentUID!).collection(user.memberId) .order(by: TIMESTAMP, descending: true) .start(afterDocument: lastMessageDoc) .limit(to: 5) } query.addSnapshotListener { (snapshot, error) in if let error = error { print("Error..\(error.localizedDescription)") self.fetchMoreDocs = false return } else if snapshot!.isEmpty { self.fetchMoreDocs = false return } else { var newMessages = Message.parseData(snapshot: snapshot) // 反转数组,将降序结果转为旧→新顺序 newMessages.reverse() // 首次加载直接赋值,加载更多追加到数组末尾 if self.messages.isEmpty { self.messages = newMessages } else { self.messages.append(contentsOf: newMessages) } DispatchQueue.main.async { self.chatRoomTV.reloadData() self.scrollToBottom() self.fetchMoreDocs = false } } } }
内容的提问来源于stack exchange,提问作者Eddie
相关产品推荐
相关产品推荐

