[英]Firebase Firestore Pagination with Swift
With my app i tried to paginate my data (10 posts per page) from Firestore using below code,使用我的应用程序,我尝试使用以下代码从 Firestore 对我的数据(每页 10 个帖子)进行分页,
import UIKit
import FirebaseFirestore
class Home: UITableViewController {
var postArray = [postObject]()
let db = Firestore.firestore()
var page : DocumentSnapshot? = nil
let pagingSpinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
override func viewDidLoad() {
super.viewDidLoad()
loadFirstPage()
}
func loadFirstPage(){
// Get the first 10 posts
db.collection("POSTS").limit(to: 10).addSnapshotListener { (snapshot, error) in
if snapshot != nil {
self.postArray = (snapshot?.documents.flatMap({postObject(dec : $0.data())}))!
// Save the last Document
self.page = snapshot?.documents.last
self.tableView.reloadData()
}
}
}
func loadNextPage(){
// get the next 10 posts
db.collection("POSTS").limit(to: 10).start(afterDocument: page!).addSnapshotListener { (snapshot, error) in
if snapshot != nil {
for doc in (snapshot?.documents)! {
self.postArray.append(postObject(dec: doc.data()))
}
self.page = snapshot?.documents.last
self.tableView.reloadData()
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as? postCell
// display data
cell?.textLabel?.text = postArray[indexPath.row].name
return cell!
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// check index to load next page
if indexPath.row < (self.postArray.count){
pagingSpinner.startAnimating()
pagingSpinner.color = UIColor.red
pagingSpinner.hidesWhenStopped = true
tableView.tableFooterView = pagingSpinner
loadNextPage()
}
}
}
But i have faced the following issues :但我遇到了以下问题:
I'm wondering why is this happening although I'm saving the last Sanpshot document as pagination cursor !我想知道为什么会发生这种情况,尽管我将最后一个 Sanpshot 文档保存为分页光标! is there a better why to implement the pagination with Swift有没有更好的理由用 Swift 实现分页
Paginating in Firestore with Swift in iOS is very straightforward if we get documents statically (using getDocuments
) and not dynamically (through a snapshot listener).如果我们静态获取文档(使用getDocuments
)而不是动态获取文档(通过快照侦听器),则在 iOS 中使用 Swift 在 Firestore 中进行分页非常简单。
We can still paginate with a snapshot listener but it requires more steps.我们仍然可以使用快照侦听器进行分页,但需要更多步骤。 That is because when a snapshot listener returns, it will return a single page of documents, and if the user has paginated through multiple pages, the update will reset the user back to a single page (this is not a very pleasant user experience).那是因为当快照监听器返回时,它会返回单页文档,如果用户分页了多个页面,更新会将用户重置回单页(这不是一个非常愉快的用户体验)。 But the workaround for this is also relatively straightforward (all we do is keep track of how many pages are rendered on screen and load that many underneath the user when a snapshot listener returns before refreshing the UI).但解决这个问题的方法也相对简单(我们所做的就是跟踪屏幕上呈现的页面数量,并在刷新 UI 之前快照侦听器返回时在用户下方加载多少页面)。
I think it's wise to split the loading of data (the first page) from the continuing of data (the additional pages) for readability.我认为将数据的加载(第一页)与数据的连续加载(附加页)分开以提高可读性是明智的。 firestoreQuery
is a Query
object that you must obviously construct on your own. firestoreQuery
是一个Query
对象,您显然必须自己构建。
class SomeViewController: UIViewController {
private var cursor: DocumentSnapshot?
private let pageSize = 10 // use this for the document-limit value in the query
private var dataMayContinue = true
/* This method grabs the first page of documents. */
private func loadData() {
firestoreQuery.getDocuments(completion: { (snapshot, error) in
...
/* At some point after you've unwrapped the snapshot,
manage the cursor. */
if snapshot.count < pageSize {
/* This return had less than 10 documents, therefore
there are no more possible documents to fetch and
thus there is no cursor. */
self.cursor = nil
} else {
/* This return had at least 10 documents, therefore
there may be more documents to fetch which makes
the last document in this snapshot the cursor. */
self.cursor = snapshot.documents.last
}
...
})
}
/* This method continues to paginate documents. */
private func continueData() {
guard dataMayContinue,
let cursor = cursor else {
return
}
dataMayContinue = false /* Because scrolling to bottom will cause this method to be called
in rapid succession, use a boolean flag to limit this method
to one call. */
firestoreQuery.start(afterDocument: cursor).getDocuments(completion: { (snapshot, error) in
...
/* Always update the cursor whenever Firestore returns
whether it's loading data or continuing data. */
if snapshot.count < self.pageSize {
self.cursor = nil
} else {
self.cursor = snapshot.documents.last
}
...
/* Whenever we exit this method, reset dataMayContinue to true. */
})
}
}
/* Let's assume you paginate with infinite scroll which means continuing data
when the user scrolls to the bottom of the table or collection view. */
extension SomeViewController {
/* Standard scroll-view delegate */
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let contentSize = scrollView.contentSize.height
if contentSize - scrollView.contentOffset.y <= scrollView.bounds.height {
didScrollToBottom()
}
}
private func didScrollToBottom() {
continueData()
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.