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

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(),会导致列表频繁刷新卡顿,还会提前结束下拉刷新状态。

修复方向

  1. 添加上拉加载更多触发逻辑,在tableView滚动到接近底部时调用fetchNotifications()
  2. 统一首次加载和分页的查询排序规则,首次加载也加上queryOrderedByKey()
  3. 在首次拉取、分页拉取拿到结果的第一时间,把返回结果里最旧条目的key赋值给currentKey作为下次分页的游标
  4. 等所有当前页数据处理完成后,再统一刷新tableView、结束刷新状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 18:57:23