使用Firebase Firestore分页- swift 4

gpfsuwkq  于 2023-02-15  发布在  Swift
关注(0)|答案(4)|浏览(165)

我正在尝试用firestore给数据分页(无限滚动我的tableview),我已经尽我所能的整合了google给的分页代码,但是我仍然不能正确的加载数据。
初始数据集根据需要加载到表视图中。然后,当用户点击屏幕底部时,下一个“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
            }

        })
    }
}
e4yzc0pl

e4yzc0pl1#

这就是我提出的解决方案!很可能这个解决方案会多次调用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
        }
    }
}
qxgroojn

qxgroojn2#

虽然有点晚了,但我还是想分享一下我是如何使用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

niknxzdl

niknxzdl3#

我的解决方案类似于@yambo,但是,我尽量避免对数据库进行额外的调用。在第一次调用数据库后,我返回10个对象,当需要加载新页面时,我会保留一个关于对象数量的参考,并检查计数+ 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()
            }
        }
    }
}
qjp7pelc

qjp7pelc4#

简单,快速和容易的方法是...
类馈送视图控制器:UI视图控制器、UI视图委托、UI视图数据源、馈送单元格委托{

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

}

相关问题