在 TableView 中无限调用分页 - Swift/Xcode

Pagination infinitely calling in TableView - Swift/Xcode

我有一个 TableView,它显示来自我的 Firebase Firestore 服务器的文档。我没有下载服务器上的所有文档,而是在用户向下滚动 TableView 时分页并下载更多文档。如果服务器上有很多文档,这会很好用。但是,如果只有几个文档,这意味着用户需要滚动浏览的文档不够多,那么会无限调用分页过程,无限地从服务器查询文档。我怎样才能解决这个问题?我知道 tableView 中的以下行有问题 willDisplayForRowAt:

if (indexPath.row == fileArray.count - 1)

我就是不知道怎么解决。

struct FileIdentifierStruct {
    var fileName = String()
    var fileDate = String()
}

var fileArray = [FileIdentifierStruct]()

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        // Trigger pagination when scrolled to last cell
        if (indexPath.row == fileArray.count - 1) {
            print("Calling paginate")
            paginate()
        }
    }

func paginate() {
        print("paginate function was called")
        // This is the main pagination code
        query = query.start(afterDocument: documents.last!)
        // For some reason calling getData here enters an infinite loop until the view is exited
        getData()
    }

func getData() {
        print("getData was called")
        query.getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err.localizedDescription)")
                let alert = SCLAlertView()
                alert.showError("ERROR", subTitle: "The following error occured while trying to retrieve the documents: \(err.localizedDescription)")
            } else {
                querySnapshot!.documents.forEach({ (document) in
//                    let data = document.data() as [String: AnyObject]
                    
                    // Set up the data modal here
                    let date = document.get("Date") as? String ?? ""
                    let id = document.documentID
                    let fileItem = FileIdentifierStruct(fileName: id, fileDate: date)
                    self.fileArray += [fileItem]
                    self.documents += [document]
                })
                self.filesTableView.reloadData()
                self.filesTableView.showDefault()
            }
        }
    }

您可以添加布尔标志:

var hasReceivedZeroResults = false

然后在收到文档列表时在 getData() 函数中:

self.hasReceivedZeroResults = querySnapshot!.documents.isEmpty

最后在 paginate() 函数的顶部插入:

guard !hasReceivedZeroResults else { return }

这里的挑战是 Firebase Firestore 中的实际数据集有未知数量的数据,所以不知道 'last row' 是什么,就没有简单的方法知道你正在显示 'last row' 分页时

几个选项:

一个常见的解决方案是让另一个集合存储您正在显示的集合的文档计数,并观察该集合的变化,以便您始终知道最后一行是什么,并且不会尝试加载更多数据当您显示最后一行数据时。

例如假设您的应用显示用户

users_collection
   user_0
      name: "Jay"
   user_1
      name: "Cindy"
   user_2
      name: "Larry"

然后是跟踪用户数量的集合

document_count
   users_collection
      count: 3

将观察者添加到 document_count、users_collection 并在添加或删除用户时,increment/decrement 计数,保留 class 变量以使该计数可用对于函数,称它为 var totalRows = 0

然后,当用户滚动到数组中的最后一行并且有更多数据可用时,就变成了仅调用分页的问题

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt...
   // Trigger pagination when scrolled to last cell & there's more rows
   if (indexPath.row == fileArray.count - 1 && lastRowDisplayedIndex < self.totalRows) {
      paginate()
   }
}

请注意,这假定您正在跟踪以某种形式显示的来自 Firestore 的行。

另一种选择是记录上次查询中读取了多少文档

query.getDocuments() { (querySnapshot, err) in
   self.lastReadCount = snapshot.count

然后当用户尝试滚动时,只有当 lastReadCount 等于您要显示的数字时才会调用分页。

例如

假设你想一次显示 5 个用户。如果显示 5 个用户,则调用 paginate 尝试再读取 5 个,如果只读取 3 个,则 self.lastReadCount 将是 3,你会知道你在列表的末尾,所以不要调用分页。