I am trying to implement pagination into my app (infinite scrolling) but I don’t seem to wrap my head around the logic. I’ve gone as far as reading the first 20 documents, then when I scroll the "Read more posts" method is called which reads The whole remaining documents (80 in this case) which is not what I want. I want to read 20 posts at a time. Here is my code please point out at what I am doing wrong:
import UIKit
import FirebaseAuth
import Firebase
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
var following = [String]()
var posts = [Post]()
var fetchingMore = false
override func viewDidLoad() {
super.viewDidLoad()
// reads first 20 posts
let db = Firestore.firestore()
db.collection("Posts").addSnapshotListener {
snapshot , error in
snapshot!.documentChanges.forEach { diff in
if (diff.type == .added) {
self.readPosts()
}
}
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let height = scrollView.frame.size.height
let contentYoffset = scrollView.contentOffset.y
let distanceFromBottom = scrollView.contentSize.height - contentYoffset
if distanceFromBottom < height {
if(!fetchingMore){
print("aaah")
beginBatchFetch()
return
}
}
}
func beginBatchFetch(){
fetchingMore = true
readMorePosts()
fetchingMore = false
}
public func readPosts(){
getFollowingList { following in
let db = Firestore.firestore()
db.collection("Posts").whereField("userId", in: following).order(by: "timestamp").limit(toLast: 20).addSnapshotListener{
posts , error in
if (error != nil){
print("253 (error!.localizedDescription)")
return
}
else{
var tempPosts = [Post]()
for doc in posts!.documents{
let daate = doc.data()["timestamp"] as! Timestamp
let mydbl = daate.dateValue().timeIntervalSince1970 * 1000
let post = Post(id: doc.data()["postId"] as! String, username: "@(doc.data()["username"]!)", userId: doc.data()["userId"] as! String , text: doc.data()["text"] as! String, timestamp: mydbl , numLikes: 0, numReposts: 0)
let isDuplicate = tempPosts.contains(where: { $0.id == post.id })
if(!isDuplicate){
tempPosts.insert(post, at: 0)
}
} // end for
self.posts = tempPosts
self.tableView.reloadData()
}
}
}
}
func getFollowingList(_ completion: @escaping (_ followingList:[String]) -> Void){
let db = Firestore.firestore()
db.collection("Following").document(Auth.auth().currentUser!.uid).collection("Follows").addSnapshotListener {
followingSnapshot , error in
if(error != nil){
print("243 (String(describing: error?.localizedDescription))")
return
}
else{
var tempFollowing = [String]()
for following in followingSnapshot!.documents{
tempFollowing.append(following.documentID)
}
return completion(tempFollowing)
}
}
}
}
func readMorePosts(){
getFollowingList { following in
let db = Firestore.firestore()
let first = db.collection("Posts").whereField("userId", in: following).order(by: "timestamp", descending: true).limit(to: 20)
first.addSnapshotListener { (snapshot, error) in
guard let snapshot = snapshot else {
print("134 (error?.localizedDescription)")
return
}
guard let lastSnapshot = snapshot.documents.last else {
return
}
// paginating ..
let next = db.collection("Posts").whereField("userId", in: following)
.order(by: "timestamp", descending: true)
.start(afterDocument: lastSnapshot)
.addSnapshotListener {
docs , err in
if err != nil{
print("152 (err!.localizedDescription)")
return
}
else{
for doc in docs!.documents{
let daate = doc.data()["timestamp"] as! Timestamp
let mydbl = daate.dateValue().timeIntervalSince1970 * 1000
let post = Post(id: doc.data()["postId"] as! String, username: "@(doc.data()["username"])" as! String, userId: doc.data()["userId"] as! String , text: doc.data()["text"] as! String, timestamp: mydbl , numLikes: 0, numReposts: 0)
let isDuplicate = self.posts.contains(where: { $0.id == post.id })
if(!isDuplicate){
self.posts.append(post)
}
} // end for
self.tableView.reloadData()
}
}
}
}
}
2
Answers
If you want to limit the number of results, you need to include a
limit
clause in your query:You’ll need to execute a query like this for every page, with an updated value for
lastSnapshot
each time.Here is my answer for FireStore pagination.
I think it can solve your problem.