Pagination with Firebase firestore - swift 4

前端 未结 4 949
情书的邮戳
情书的邮戳 2021-02-03 15:08

I\'m trying to paginate data (infinitely scroll my tableview) using firestore. I\'ve integrated the code google gives for pagination as best I can, but I\'m still having problem

相关标签:
4条回答
  • 2021-02-03 15:46

    Simple, Fast and easy way is...

    class 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")
        }
    }
    

    }

    0 讨论(0)
  • 2021-02-03 15:48

    A little late in the game, but I would like to share how I do it, using the query.start(afterDocument:) method.

    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()
            }
        }
    }
    

    Result like so:

    Here is a reference.

    0 讨论(0)
  • 2021-02-03 15:51

    My solution was similar to @yambo, however, I tried to avoid making extra calls to the database. After the first call to the database, I get back 10 objects and when it is time to load the new page I kept a reference of how many objects and I checked if the count + 9 is in the range of my new count.

        @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()
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-03 15:58

    So here's the solution I've come up with! It is very likely that this solution makes multiple calls to firestore, creating a large bill for any real project, but it works as a proof of concept I guess you could say.

    If you have any recommendations or edits, please feel free to share!

    Here's how all the variables were initialized:

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

    If you have any recommendations or edits, please feel free to share!

    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
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题