Swift iOS:Firebase分页

jhn*_*ris 11 ios firebase swift firebase-realtime-database

我有这个Firebase数据:

Firebase数据

我想posts通过分页查询数据.目前我的代码是将这个JS代码转换为Swift代码

let postsRef = self.rootDatabaseReference.child("development/posts")
postsRef.queryOrderedByChild("createdAt").queryStartingAtValue((page - 1) * count).queryLimitedToFirst(UInt(count)).observeSingleEventOfType(.Value, withBlock: { snapshot in
....

  })
Run Code Online (Sandbox Code Playgroud)

访问时,此数据page: 1, count: 1.我可以获取"posts.a"的数据但是当我尝试访问page: 2, count: 1返回时仍然是"posts.a"

我在这里错过了什么?

tim*_*ous 16

假设您childByAutoId()在将数据推送到Firebase时正在或将要使用,您可以使用queryOrderedByKey()按时间顺序排序数据.文件在这里.

唯一键基于时间戳,因此列表项将按时间顺序自动排序.

要开始使用特定密钥,您必须附加查询queryStartingAtValue(_:).

样品用法:

var count = numberOfItemsPerPage

var query ref.queryOrderedByKey()

if startKey != nil {
  query = query.queryStartingAtValue(startKey)
  count += 1
}

query.queryLimitedToFirst(UInt(count)).observeSingleEventOfType(.Value, withBlock: { snapshot in
  guard var children = snapshot.children.allObjects as? [FIRDataSnapshot] else {
    // Handle error
    return
  }

  if startKey != nil && !children.isEmpty {
    children.removeFirst()
  }

  // Do something with children
})
Run Code Online (Sandbox Code Playgroud)

  • 什么是startKey?n我应该把这段代码放在哪里。 (2认同)
  • 请解释或显示更多代码。如果你们不介意的话...与 firebase 分页战斗让我很困惑 (2认同)

Gau*_*ana 5

我知道我有点晚了,timominous有一个很好的答案,但我想分享我解决这个问题的方法。这是一个完整的示例,它不仅与分页有关。这个例子在 Swift 4 中,我使用了一个名为 CodableFirebase 的库(你可以在这里找到它)来解码 Firebase 快照值。

除了这些之外,请记住在创建帖子并将该键存储在 postId(或您的变量)中时使用 childByAutoId。因此,我们可以稍后使用它。

现在,模型看起来像这样......

    class FeedsModel: Decodable {
        var postId: String!
        var authorId: String! //The author of the post
        var timestamp: Double = 0.0 //We'll use it sort the posts.
        //And other properties like 'likesCount', 'postDescription'...
    }
Run Code Online (Sandbox Code Playgroud)

我们将使用此功能以最近的第一种方式获取帖子

    class func getFeedsWith(lastKey: String?, completion: @escaping ((Bool, [FeedsModel]?) -> Void)) {
        let feedsReference = Database.database().reference().child("YOUR FEEDS' NODE")
        let query = (lastKey != nil) ? feedsReference.queryOrderedByKey().queryLimited(toLast: "YOUR NUMBER OF FEEDS PER PAGE" + 1).queryEnding(atValue: lastKey): feedsReference.queryOrderedByKey().queryLimited(toLast: "YOUR NUMBER OF FEEDS PER PAGE")
        //Last key would be nil initially(for the first page).

        query.observeSingleEvent(of: .value) { (snapshot) in
            guard snapshot.exists(), let value = snapshot.value else {
                completion(false, nil)
                return
            }
            do {
                let model = try FirebaseDecoder().decode([String: FeedsModel].self, from: value)
                //We get the feeds in ['childAddedByAutoId key': model] manner. CodableFirebase decodes the data and we get our models populated.
                var feeds = model.map { $0.value }
                //Leaving the keys aside to get the array [FeedsModel]
                feeds.sort(by: { (P, Q) -> Bool in P.timestamp > Q.timestamp }) 
                //Sorting the values based on the timestamp, following recent first fashion. It is required because we may have lost the chronological order in the last steps.
                if lastKey != nil { feeds = Array(feeds.dropFirst()) }
                //Need to remove the first element(Only when the lastKey was not nil) because, it would be the same as the last one in the previous page.
                completion(true, feeds)
                //We get our data sorted and ready here.
            } catch let error {
                print("Error occured while decoding - \(error.localizedDescription)")
                completion(false, nil)
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在,在我们的 viewController 中,对于初始加载,函数调用在 viewDidLoad 中是这样的。当 tableView 将显示单元格时,将获取下一页...

    class FeedsViewController: UIViewController {

        //MARK: - Properties
        @IBOutlet weak var feedsTableView: UITableView!

        var dataArray = [FeedsModel]()
        var isFetching = Bool()
        var previousKey = String()
        var hasFetchedLastPage = Bool()


        //MARK: - ViewController LifeCycle
        override func viewDidLoad() {
            super.viewDidLoad()
            //Any other stuffs..
            self.getFeedsWith(lastKey: nil) //Initial load.
        }

        //....

        func getFeedsWith(lastKey: String?) {

            guard !self.isFetching else {
                self.previousKey = ""
                return
            }
            self.isFetching = true

            FeedsModel.getFeedsWith(lastKey: lastKey) { (status, data) in
                self.isFetching = false
                guard status, let feeds = data else {
                    //Handle errors
                    return
                }

                if self.dataArray.isEmpty { //It'd be, when it's the first time.
                    self.dataArray = feeds
                    self.feedsTableView.reloadSections(IndexSet(integer: 0), with: .fade)
                } else {
                    self.hasFetchedLastPage = feeds.count < "YOUR FEEDS PER PAGE"
                    //To make sure if we've fetched the last page and we're in no need to call this function anymore.
                    self.dataArray += feeds
                   //Appending the next page's feed. As we're getting the feeds in the recent first manner.
                    self.feedsTableView.reloadData()
                }
            }
        }

        //MARK: - TableView Delegate & DataSource

        //....

        func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            if self.dataArray.count - 1 == indexPath.row && !self.hasFetchedLastPage {
            let lastKey = self.dataArray[indexPath.row].postId
            guard lastKey != self.previousKey else { return }
            //Getting the feeds with last element's postId. (postId would be the same as a specific node in YourDatabase/Feeds).
            self.getFeedsWith(lastKey: lastKey)
            self.previousKey = lastKey ?? ""
        }

        //....
    }
Run Code Online (Sandbox Code Playgroud)