【问题标题】:Pagination with Firebase firestore - swift 4使用 Firebase Firestore 进行分页 - swift 4
【发布时间】:2019-02-11 00:12:04
【问题描述】:

我正在尝试使用 Firestore 对数据进行分页(无限滚动我的表格视图)。我已尽我所能集成了谷歌为分页提供的代码,但我仍然无法正确加载数据。

初始数据集根据需要加载到 tableview 中。然后,当用户点击屏幕底部时,下一个“x”数量的项目被加载。但是当用户第二次点击屏幕底部时,相同的“x”项目被简单地附加到表格中看法。相同的项目会无限期地添加。

所以它最初的 3 个“骑行”对象,接下来的 4 个“骑行”对象永远重复。

123 4567 4567 4567 4567...

如何让数据正确加载?

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offsetY = scrollView.contentOffset.y
    let contentHeight = scrollView.contentSize.height

    if offsetY > contentHeight - scrollView.frame.height {
        // Bottom of the screen is reached
        if !fetchingMore {
            beginBatchFetch()
        }
    }
}

func beginBatchFetch() {
    // Array containing "Ride" objcets is "rides"

    fetchingMore = true

    // Database reference to "rides" collection
    let ridesRef = db.collection("rides")

    let first = ridesRef.limit(to: 3)

    first.addSnapshotListener { (snapshot, err) in
        if let snapshot = snapshot {
            // Snapshot isn't nil
            if self.rides.isEmpty {
                // rides array is empty (initial data needs to be loaded in).
                let initialRides = snapshot.documents.compactMap({Ride(dictionary: $0.data())})
                self.rides.append(contentsOf: initialRides)
                self.fetchingMore = false
                DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
                    self.tableView.reloadData()
                })
                print("first rides loaded in")
            }
        } else {
            // Error
            print("Error retreiving rides: \(err.debugDescription)")
            return
        }

        // reference to lastSnapshot
        guard let lastSnapshot = snapshot!.documents.last else{
            // The collection is empty
            return
        }


        let next = ridesRef.limit(to: 4).start(afterDocument: lastSnapshot)

        next.addSnapshotListener({ (snapshot, err) in
            if let snapshot = snapshot {

                if !self.rides.isEmpty {

                    let newRides = snapshot.documents.compactMap({Ride(dictionary: $0.data())})
                    self.rides.append(contentsOf: newRides)
                    self.fetchingMore = false
                    DispatchQueue.main.asyncAfter(deadline: .now() + 7, execute: {
                        self.tableView.reloadData()
                    })

                    print("new items")
                    return
                }
            } else {
                print("Error retreiving rides: \(err.debugDescription)")
                return
            }

        })
    }
}

【问题讨论】:

    标签: swift firebase pagination google-cloud-firestore infinite-scroll


    【解决方案1】:

    这就是我想出的解决方案!该解决方案很可能会多次调用 firestore,从而为任何实际项目创建大笔账单,但我猜你可以说它是一个概念证明。

    如果您有任何建议或修改,请随时分享!

    所有变量的初始化方式如下:

    var rides = [Ride]()
    var lastDocumentSnapshot: DocumentSnapshot!
    var fetchingMore = false
    

    如果您有任何建议或修改,请随时分享!

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offsetY = scrollView.contentOffset.y
        let contentHeight = scrollView.contentSize.height
        //print("offsetY: \(offsetY) | contHeight-scrollViewHeight: \(contentHeight-scrollView.frame.height)")
        if offsetY > contentHeight - scrollView.frame.height - 50 {
            // Bottom of the screen is reached
            if !fetchingMore {
                paginateData()
            }
        }
    }
    
    // Paginates data
    func paginateData() {
    
        fetchingMore = true
    
        var query: Query!
    
        if rides.isEmpty {
            query = db.collection("rides").order(by: "price").limit(to: 6)
            print("First 6 rides loaded")
        } else {
            query = db.collection("rides").order(by: "price").start(afterDocument: lastDocumentSnapshot).limit(to: 4)
            print("Next 4 rides loaded")
        }
    
        query.getDocuments { (snapshot, err) in
            if let err = err {
                print("\(err.localizedDescription)")
            } else if snapshot!.isEmpty {
                self.fetchingMore = false
                return
            } else {
                let newRides = snapshot!.documents.compactMap({Ride(dictionary: $0.data())})
                self.rides.append(contentsOf: newRides)
    
                //
                DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
                    self.tableView.reloadData()
                    self.fetchingMore = false
                })
    
                self.lastDocumentSnapshot = snapshot!.documents.last
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      我的解决方案类似于@yambo,但是,我尽量避免对数据库进行额外调用。在第一次调用数据库后,我得到了 10 个对象,当该加载新页面时,我保留了多少对象的引用,并检查了 count + 9 是否在我的新计数范围内。

          @objc func LoadMore() {
          let oldCount = self.uploads.count
          guard shouldLoadMore else { return }
          self.db.getNextPage { (result) in
              switch result {
              case .failure(let err):
                  print(err)
              case .success(let newPosts):
                  self.uploads.insert(contentsOf: newPosts, at: self.uploads.count)
                  if oldCount...oldCount+9 ~= self.uploads.count {
                      self.shouldLoadMore = false
                  }
                  DispatchQueue.main.async {
                      self.uploadsView.collectionView.reloadData()
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        游戏有点晚了,但我想分享一下我是如何做到的,使用 query.start(afterDocument:) 方法。

        class PostsController: UITableViewController {
        
            let db = Firestore.firestore()
        
            var query: Query!
            var documents = [QueryDocumentSnapshot]()
            var postArray = [Post]()
        
            override func viewDidLoad() {
                super.viewDidLoad()
        
                query = db.collection("myCollection")
                          .order(by: "post", descending: false)
                          .limit(to: 15)
        
                getData()
            }
        
            func getData() {
                query.getDocuments() { (querySnapshot, err) in
                    if let err = err {
                        print("Error getting documents: \(err)")
                    } else {
                        querySnapshot!.documents.forEach({ (document) in
                            let data = document.data() as [String: AnyObject]
        
                            //Setup your data model
        
                            let postItem = Post(post: post, id: id)
        
                            self.postArray += [postItem]
                            self.documents += [document]
                        })
                        self.tableView.reloadData()
                    }
                } 
            }
        
            func paginate() {
                //This line is the main pagination code.
                //Firestore allows you to fetch document from the last queryDocument
                query = query.start(afterDocument: documents.last!)
                getData()
            }
        
            override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                return postArray.count
            }
        
            override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
                // Trigger pagination when scrolled to last cell
                // Feel free to adjust when you want pagination to be triggered
                if (indexPath.row == postArray.count - 1) {
                    paginate()
                }
            }
        }
        

        结果如下:

        这是reference

        【讨论】:

        • 我见过的手动 UITableView 分页的最佳答案。
        • 这是一个很好的答案。我遇到了此处使用的 WillDisplay 的问题,因此我选择使用 scrollViewDidScroll(例如:stackoverflow.com/a/41255637/9339880),并添加一个小延迟以避免底部检测重复,但这是一个很好的基础。
        【解决方案4】:

        简单、快速、简单的方法是......

        类 FeedViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, FeedCellDelegate {

        private var quotes = [Quote]() {
            
            didSet{ tbl_Feed.reloadData() }
        }
        
        var quote: Quote?
        var fetchCount = 10
        
        @IBOutlet weak var tbl_Feed: UITableView!
        
        override func viewDidLoad() {
            super.viewDidLoad()
        
            fetchPost() 
        }
        
        
        // MARK: - API
        
        func fetchPost() {
            
            reference(.Quotes).limit(to: getResultCount).getDocuments { (snapshot, error) in
                
                guard let documents = snapshot?.documents else { return }
                
                documents.forEach { (doc) in
                    
                    let quotes = documents.map {(Quote(dictionary: $0.data()))}
                    
                    self.quotes = quotes
                }
            }
        }  
        
        func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
            
            let currentOffset = scrollView.contentOffset.y
            let maxxOffset = scrollView.contentSize.height - scrollView.frame.size.height
            
            if maxxOffset - currentOffset <= 300 { // Your cell size 300 is example
        
                fetchCount += 5
                fetchPost()
        
                print("DEBUG: Fetching new Data")
            }
        }
        

        }

        【讨论】:

          猜你喜欢
          • 2018-04-23
          • 2020-08-25
          • 2017-01-01
          • 1970-01-01
          • 2021-12-10
          • 1970-01-01
          • 2021-03-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多