Swift结合Firebase实现数据分页不生效问题
Firebase通知分页逻辑else分支不触发问题修复
问题现象
实现通知列表分页拉取逻辑时,首次加载正常,已确认currentKey在首次加载完成后被正确赋值,但分页逻辑所在的else分支始终无法执行。相关代码如下:
var currentKey: String? func fetchNotifications() { guard let currentUid = Auth.auth().currentUser?.uid else { return } if currentKey == nil { //initial data pull NOTIFICATIONS_REF.child(currentUid).queryLimited(toLast: 16).observeSingleEvent(of: .value) { (snapshot) in guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return } guard let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return } allObjects.forEach({ (snapshot) in let notificationId = snapshot.key guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return } guard let uid = dictionary["uid"] as? String else { return } Database.fetchUser(with: uid, completion: { (user) in // if notification is for post if let postId = dictionary["postId"] as? String { Database.fetchPost(with: postId, completion: { (post) in let notification = Notification(user: user, post: post, dictionary: dictionary) if notification.notificationType == .Comment { self.getCommentData(forNotification: notification) } self.notifications.append(notification) self.notifications.sort { (notification1, notification2) in return notification1.creationDate > notification2.creationDate } self.tableView.reloadData() }) } else { let notification = Notification(user: user, dictionary: dictionary) self.notifications.append(notification) self.notifications.sort { (notification1, notification2) in return notification1.creationDate > notification2.creationDate } self.tableView.reloadData() self.tableView.refreshControl?.endRefreshing() } }) }) self.tableView.refreshControl?.endRefreshing() } } else { NOTIFICATIONS_REF.child(currentUid).queryOrderedByKey().queryEnding(atValue: self.currentKey).queryLimited(toLast: 3).observeSingleEvent(of: .value) { (snapshot) in guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return } guard let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return } allObjects.forEach({ (snapshot) in let notificationId = snapshot.key guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return } guard let uid = dictionary["uid"] as? String else { return } Database.fetchUser(with: uid, completion: { (user) in if notificationId != self.currentKey { // if notification is for post if let postId = dictionary["postId"] as? String { Database.fetchPost(with: postId, completion: { (post) in let notification = Notification(user: user, post: post, dictionary: dictionary) if notification.notificationType == .Comment { self.getCommentData(forNotification: notification) } self.notifications.append(notification) self.notifications.sort { (notification1, notification2) in return notification1.creationDate > notification2.creationDate } self.tableView.reloadData() }) } else { let notification = Notification(user: user, dictionary: dictionary) self.notifications.append(notification) self.notifications.sort { (notification1, notification2) in return notification1.creationDate > notification2.creationDate } self.tableView.reloadData() self.tableView.refreshControl?.endRefreshing() } } }) }) } } }
核心原因
- 最直接的触发问题:你仅在
viewDidLoad中调用了一次fetchNotifications()。函数是单次同步执行的,第一次调用时currentKey为nil,直接进入if分支执行异步网络请求,后续即使你在异步回调里给currentKey赋值,函数已经执行完毕退出,不会自动重新走判断逻辑进入else分支。必须在滚动到列表底部、需要加载下一页数据时,再次手动调用fetchNotifications(),才会重新判断currentKey状态,进入分页逻辑。 - 查询规则不匹配:首次拉取只写了
queryLimited(toLast: 16),没有显式调用queryOrderedByKey(),但分页查询用了queryOrderedByKey()。Firebase Realtime Database未指定排序规则时默认按priority排序,和分页查询的排序逻辑不一致,会导致游标错位。 - 游标赋值缺失/时序错误:首次拉取的回调里你拿到了
first(返回结果中key最小、也就是最旧的那条数据),但没有在主线程同步给self.currentKey = first.key,如果是在其他异步位置赋值,很可能出现取值时序问题。 - 额外的性能/逻辑问题:你在遍历每条数据的回调里都调用
tableView.reloadData()和refreshControl.endRefreshing(),会导致列表频繁刷新卡顿,还会提前结束下拉刷新状态。
修复方向
- 添加上拉加载更多触发逻辑,在tableView滚动到接近底部时调用
fetchNotifications() - 统一首次加载和分页的查询排序规则,首次加载也加上
queryOrderedByKey() - 在首次拉取、分页拉取拿到结果的第一时间,把返回结果里最旧条目的key赋值给
currentKey作为下次分页的游标 - 等所有当前页数据处理完成后,再统一刷新tableView、结束刷新状态
内容的提问来源于stack exchange,提问作者Jlls
相关产品推荐
相关产品推荐

