MJQZ1347 MJQZ1347 - 1 year ago 216
iOS Question

Firebase: How to use observeSingleEventOfType for latest server data when persistance is enabled?

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

, 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
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

} else {
print("snapshot exists")

I also tried
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
.observeSingleEventOfType(.Value, withBlock: { (snapshot) -> Void in

here would lead to downloading all messages in
, which is not wanted at all.

So is there a clever workaround for these two scenarios? Any help is appreciated.

Answer Source

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 {
    } else if !success || snapshot == nil {

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