1

I've been having this issue at random times for quite a while, where I will physically be looking at my firebase console and see that I have deleted a piece of data, and then in code I will call print(snapshot.ref) and see the correct reference (copy and pasted in browser to double check too), yet somehow when I try to get the values of the snapshot/iterate over its children the snapshot is containing old data that is not in the database anymore.

let key2 = ref.child(users).child("Employees").observeSingleEvent(of: FIRDataEventType.value, with: { (snapshot) in


            print(snapshot)

            for child in snapshot.children
            {

                self.nameList.append((child as AnyObject).value)
            }


     })

So here my database looks like this: (picture is cut off but there's no children under it)

enter image description here

Yet somehow when I print snapshot I get:

Snap (Employees) {
    0 = "";
    1 = "name1";
    2 = "name1";
}

This has been frustrating me for a while, it seems like it could have something to do with old snapshot values somehow being stored locally or somehow not seeing the most up to date version of the database. If it matters I have similar calls to .observeSingleEvent in this file, the one copy and pasted above is nested within another. Even if it were a synchronization problem, I still don't know how that could make the printed value the old value.

Any help would be so so appreciated.

AL.
  • 36,815
  • 10
  • 142
  • 281
Alex
  • 299
  • 3
  • 16

1 Answers1

2

This behavior is apparently by design. It's so strange that I actually contacted Firebase Support about it, and was told that they'd consider revising either the behavior or the docs, but couldn't promise a date and I should monitor their Release Notes URL for updates to it.

It makes a little sense if you consider it from the SDK point of view. You're calling observeSingleEvent. To Firebase this means they should only call you ONE TIME. Developers would probably find it confusing if a method with that name produced more than one callback, right?

But if you have persistence enabled things get a little weird. Just like with observeEventOfType, Firebase will give you the on-disk value immediately so you get the fastest UI update, but then it will call the server for a fresher value to be sure it has the latest data from then on. The problem is, since you're telling it not to call you back with this data, it will remember it (so you WILL see it in the future, which is why it seems confusing) but not tell you that it's arrived.

What I've discovered through some trial and error is that the instinctive drive to use observeSingleEvent may be misguided with Firebase anyway. Both iOS and Android uses "recycler" view mechanisms for table/collection views such that only a handful of items are actually in-memory at a time anyway, even on screens with a lot of data. Beyond this built-in efficiency from the platform, Firebase itself seems to work just fine even managing many dozens of in-memory refs at a time. In my apps, I've taken to just using observeEventOfType for all of my use-cases except where I have a very specific, and not theoretical-efficiency-related reason, to use observeSingleEvent. The app performance has been minimal, and the data then works much more the way you expect.

Chad Robinson
  • 4,575
  • 22
  • 27
  • Sorry that you bumped into this Chad. I've indeed been preaching for a few years (pretty much since we launched disk persistence) that disk persistence and single value event listeners don't mix well. In general we recommend using regular listeners/observers, because it's what our database was made for. But especially when using disk persistence: don't combine it with single value event listeners. See my longer explanation here: http://stackoverflow.com/questions/34486417/firebase-offline-capabilities-and-addlistenerforsinglevalueevent/34487195#34487195 – Frank van Puffelen Feb 24 '17 at 05:46
  • Thanks, Frank. Should we change how this question here was answered? Yours is a bit more detailed, and makes this one pretty much a straight duplicate question. IMO, the important detail is that Firebase honors the INTENT of the NAME of the method: It provides a single callback. Period. What's less clear is that a server call will still be made to obtain updated data, but the persisted data is immediately returned. – Chad Robinson Feb 24 '17 at 17:41
  • I mostly care that people can find the best info. So we can mark yours as a duplicate to make that more explicit. But since you didn't find my answer in time, having your question around too is a Good Thing (tm). – Frank van Puffelen Feb 24 '17 at 18:40
  • This clears things up, thank you. I personally think this behavior is pretty counterintuitive and I wish it were different, I will try disabling persistence. May I ask since you say you now use many calls to .observeEventOfType, have you never ran into this issue since? If I remember correctly I had tried using this instead , and had some simliar issues. Does .observeEventOfType always get the most up to date value? If I want to continue to use observeSingleEvent, could I just disable persistence? – Alex Feb 24 '17 at 19:42
  • Also, when I tried using ObserveEventOfType, I had problems with if I modified/deleted data in the future, some other listener that was still running would try to execute and throw a null pointer error. I wish there were a simpler way to simply read a piece of data as it is currently and then be finished. – Alex Feb 24 '17 at 19:48