I\'m trying to order my data from Firebase so the most recent post is at the top (like Instagram), but I just can\'t get it to work properly. Should I be using a server time
Based on @tobeiosdev answer i define my data structure like this:
"posts" : {
"-KcOa8GXBl08V-WXeX8P" : {
"author" : "@giovanny.piñeros",
"hashtags" : [ "Hello", "World" ],
"text" : "Hola Mundo!!!!!",
"timestamp" : 5.08180914309278E8,
"title" : "Hello World",
"userid" : "hmIWbmQhfgh93"
}
As you can see i've added a timestamp attribute, when i query my data with a child added event, i pass that data to a post object, then i append that object to an array of posts from which my table view will feed:
self.posts.append(post)
self.posts.sort(by: {$0.timestamp! > $1.timestamp!})
self.tableViewFeed.reloadData()
With the sort method i've managed to order my data in the desire order of posts, from the newest to the oldest. I Hope this approach could help anyone :).
Using only reverse() for your array is not enough way to encompass everything. There are different things you need to think about:
Limit while retrieving data, use append() and then reverse() to save time. You don't need to delete all array for each time.
Scroll trigger or willDisplay cell method loading
Let's start. You can create a child for your posts timestamp or date/time being global. To provide like Instagram seconds, weeks I advice you using UTC time. So I will call this: (timeUTC)
For sorting your all post, use since1970 timestamp. So I will call this (timestamp) and then also you can keep another node as (reversedTimestamp) adding - prefix to timestamp. So when you use queryOrdered to this node. You can handle latest 5 post using with yourQuery.queryLimited(toFirst: 5)
.
1.Get UTC date/time for timeUTC node in Swift 3:
let date = Date()
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
formatter.timeZone = TimeZone(abbreviation: "UTC")
let utcTimeZoneStr = formatter.string(from: date)
+0000 means it's universal time, look at http://time.is/tr/UTC
2.Get since1970 timestamp to sort posts in Swift 3:
let timestamp = (Date().timeIntervalSince1970 as NSString).doubleValue
let reversedTimestamp = -1.0 * timestamp
Now, you can save them on your Firebase posts like this.
"posts" : {
"-KHLOy5mOSq0SeB7GBXv" : {
"timestamp": "1475858019.2306"
"timeUTC" : "2012-02-04 12:11:56 +0000"
},
"-KHLrapS0wbjqPP5ZSUY" : {
"timestamp": "1475858010.1245"
"timeUTC" : "2014-02-04 12:11:56 +0000"
},
I will retrieve five by five post, so I'm doing queryLimited(toFirst: 5) in viewDidLoad
:
let yourQuery = ...queryOrdered(byChild: "reverseTimestamp")
.queryEnding(atValue: "\(self.pageOnTimestamp)", childKey: "reverseTimestamp")
yourQuery.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.value is NSNull {
print("There is no post.")
}
else {
yourQuery.queryLimited(toFirst: 5).observeSingleEvent(of: .value, with: { (snapshot) in
self.posts.removeAll(keepingCapacity: true)
for (i, snap) in snapshot.children.enumerated() {
if let postAllDict = snapshot.value as? [String: AnyObject] {
if let postDict = postAllDict[(snap as AnyObject).key as String] as? [String: AnyObject] {
let post = Post(key: (snap as AnyObject).key as String, postDict: postDict)
self.posts.append(post)
}
}
}
completion(true)
})
}
})
If user reached latest post, you can handle it with willDisplay
method like below, then you can call loadMore function.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if self.posts.count - 1 == indexPath.row {
// call loadMore function.
}
}
In loadMore() function you can handle latest post's timestamp, then start-end query as with that, so you can easily continue with next first 5 posts while appending before array.
For Swift 3 conversion as nice formatted, take a look here: Swift 3 - UTC to time ago label, thinking 12h / 24h device time changes