I really enjoy coding with Firebase. It's a great backend with a variety of different toolsets. But I miss a simple way to check a path for updated data when persistance is enabled. I think that this is not a seldom usecase, because I often need my app to act in a certain way depending on the latest server data, that only need to be read once.
I would usually use observeSingleEventOfType
, but it's quite useless when perisistance is enabled, since it will never retrieve the latest server data. Which I don't understand why. There should be an option added to skip the local cache and only look for server data.
Disabling persistance solves this problem and observeSingleEventOfType
will work as expected. But that would mean that one needs to reimplement all the offline capabilities on his own.
First scenario:
// chats contain meta information about the chat like last message and count of unread messages
let chatRef = ref.child("chats").child(receiverId).child(chatId)
chatRef.observeSingleEventOfType(.Value, withBlock: { (snapshot) -> Void in
if !snapshot.exists() {
print("snapshot does not exist")
// the other side has deleted the chat
// now delete all messages and member objects
ref.child("messages").child(chatId).setValue(nil)
ref.child("members").child(chatId).setValue(nil)
} else {
print("snapshot exists")
}
})
I also tried chatRef.keepSynced(true)
before observing for events with no luck. Which doesn't make sense in all situations anyway:
Second scenario:
func removeOlderMessages() {
let dateInThePast = NSDate().addDays(-30).timeIntervalSince1970 * 1000
self.messagesRef.queryOrderedByChild("timestamp")
.queryEndingAtValue(dateInThePast)
.observeSingleEventOfType(.Value, withBlock: { (snapshot) -> Void in
snapshot.ref.removeValue()
})
}
Using keepSynced
here would lead to downloading all messages in messagesRef
, which is not wanted at all.
So is there a clever workaround for these two scenarios? Any help is appreciated.
Ok, I think I found a reasonable workaround for both scenarios:
Workaround for first scenario:
Use transactions
. They will only work when you are online. The completition
block will return the latest server data.
self.ref.child("chats").child(receiverId).child(chatId).runTransactionBlock({ (currentData) -> FIRTransactionResult in
// Actually do nothing with the retrieved data and re-submit it.
return FIRTransactionResult.successWithValue(currentData)
}) { (error, success, snapshot) in
if let error = error {
print(error)
return
} else if !success || snapshot == nil {
return
}
// snapshot contains the latest server data
if !snapshot!.exists() {
// the other side has deleted the chat
// now delete all messages and member objects
print("snapshot doesn't exist. deleting messages and members.")
ref.child("messages").child(chatId).setValue(nil)
ref.child("members").child(chatId).setValue(nil)
} else {
print("snapshot exists. not deleting all messages and members.")
}
}
The downside is that it will take considerably longer to retrieve the data compared to observeEventType
or observeSingleEventOfType
.
Workaround for second scenario:
Use observeEventType(.Value)
. It will first return the cached and then latest server data if available. The observer can be removed after a set time interval with NSTimer
.
All in all these workarounds are ok for now, but a function to skip the local cache when using observeSingleEventOfType
is indispensable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With