user
user

Reputation: 445

Paginate posts to collection view with firebase & swift

I'm trying to paginate posts that users are following to my collection view from my firebase database. Currently only 4 posts are being appended to the collection view and not loading anymore when I scroll down.

I've tried changing the number of posts loaded initially with no luck.

fileprivate func fetchFollowingUserIds() {

    guard let uid = Auth.auth().currentUser?.uid else { return }
    Database.database().reference().child("user-following").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in

        guard let userIdsDictionary = snapshot.value as? [String: Any] else { return }

        userIdsDictionary.forEach({ (key, value) in
            Database.fetchUserWithUID(uid: key, completion: { (user) in
                self.fetchPostsWithUser(user: user)
            })
        })

    }) { (err) in
        print("Failed to fetch following user ids:", err)
    }
}

var posts = [Post]()
fileprivate func fetchPosts() {
    guard let uid = Auth.auth().currentUser?.uid else { return }

    Database.fetchUserWithUID(uid: uid) { (user) in
        self.fetchPostsWithUser(user: user)
    }
}

var isFinishedPaging = false
fileprivate func fetchPostsWithUser(user: User) {

    self.collectionView?.refreshControl?.endRefreshing()

    let ref = Database.database().reference().child("posts").child(user.uid)

    var query = ref.queryOrdered(byChild: "creationDate")

    if posts.count > 0 {
        let value = posts.last?.creationDate.timeIntervalSince1970
        query = query.queryEnding(atValue: value)
    }

    query.queryLimited(toLast: 4).observeSingleEvent(of: .value, with: { (snapshot) in

        guard var allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }

        allObjects.reverse()

        if allObjects.count < 4 {
            self.isFinishedPaging = true
        } else {
            self.isFinishedPaging = false
        }
        if self.posts.count > 0 && allObjects.count > 0 {
            allObjects.removeFirst()
        }

        allObjects.forEach({ (snapshot) in
            guard let dictionary = snapshot.value as? [String: Any] else { return }
            var post = Post(user: user, dictionary: dictionary)

            post.id = snapshot.key

            self.posts.append(post)
        })

        self.collectionView?.reloadData()

    }) { (err) in
        print(err)
    }
}

I simply want it to load more posts when the user scrolls down.

Upvotes: 1

Views: 116

Answers (1)

Jay
Jay

Reputation: 35658

There may be a query issue or a potential logic issue. Lets assume you want to present posts to the user, with the most recent at the top of the list and allow the user to scroll down to see earlier posts.

Let's address both with an example:

We don't have your structure but keeping it super simple, suppose your posts have the following structure with creation dates

post_0
   creation_date: "20180101"
post_1
   creation_date: "20180102"
post_2
   creation_date: "20180103"
post_3
   creation_date: "20180104"
post_4
   creation_date: "20180105"
post_5
   creation_date: "20180106"
post_6
   creation_date: "20180107"
post_7
   creation_date: "20180108"

Here's your initial query, order by creation date, which will load the last 4 posts from the 5th to the 8th

var query = ref.queryOrdered(byChild: "creationDate")

Then subsequent queries are ordered by creation date but the ending value is not the creation date but the time elapsed since 1970 of the creation date.

let value = posts.last?.creationDate.timeIntervalSince1970
var query = ref.queryOrdered(byChild: "creationDate").queryEnding(atValue: value)

I would guess you just want to load the next 4 earlier posts. So as this sit in the array, they look like this:

20180108
20180107
20180106
20180105

One way to do that is the get the creationDate of the last post from your dataSource (which will be the oldest post)

20180105

Then query by creationDate, endingAt the creation date of the last post, getting 5 total posts, then remove the last one

20180101
20180102
20180103
20180104
20180105

then reversed

20180105
20180104
20180103
20180102
20180101

and remove the first

20180104
20180103
20180102
20180101

something like this

let lastD = self.postsArray.last
self.postsArray = []

let postsRef = self.ref.child("posts")
let queryRef = postsRef.queryOrdered(byChild: "creation_date")
let queryEndingRef = queryRef.queryEnding(atValue: lastD)
let queryLimitedRef = queryEndingRef.queryLimited(toLast: 5)
queryLimitedRef.observeSingleEvent(of: .value, with: { snapshot in
    guard var thisArray = snapshot.children.allObjects as? [DataSnapshot] else { return }

    thisArray.reverse()
    thisArray.removeFirst()

    for post in thisArray {
        let theDate = post.childSnapshot(forPath: "creation_date").value as! String
        self.postsArray.append(theDate)
    }
})

Upvotes: 2

Related Questions