Just How Persistent Are Firebase Database Observers

Just how persistent are Firebase database observers?

While the listener may stay active in your single test case, you should not rely on Firebase Database listeners for background data delivery.

The listener stays active as long as the connection stays open. It is up to the operating system to determine when it closes the connection. There is a good chance that the iOS emulator has different behavior in this case than a physical device would have.

What actually happens when persistence is enabled in Firebase?

It's actually pretty simple. When you attach an observer (whether using observeEventType or observeSingleEventOfType), Firebase will:

  1. Immediately raise events with any complete cached data.
  2. Request updated data from the server and, when it arrives, raise new events if the data is different than what was cached.

There are a couple subtleties that fall out of this though:

  • We'll only raise events with cached data if it is complete. This means:

    • If we have no cached data (you haven't observed this location before), we will not raise events with null or similar. You won't get any events until we get data from the server.
    • If you have partial data for this location (e.g. you observed /foo/bar previously but now you're observing /foo), you will get ChildAdded events for complete children (e.g. /foo/bar), but you won't get a Value event (e.g. for /foo) until we've gotten complete data from the server for the location you're observing.
  • If you're using observeSingleEventOfType, you're explicitly asking for only a single event and so if you have cached data, #1 will happen but #2 will not, which may not be what you want (you'll never see the latest server data).

Hope this helps!

Firebase iOS data observers not responding periodically on iPhone

Finally we got the issue resolved. It was related to auth token issue.

Saw more info about the actual issue by enabling logging in Firebase, through

FIRDatabase.setLoggingEnabled(true) 

In the logs we saw messages:

Error fetching token: Error Domain=FIRAuthErrorDomain Code=17011 "There is no user record corresponding to this identifier. The user may have been deleted." UserInfo={NSLocalizedDescription=There is no user record corresponding to this identifier. The user may have been deleted., error_name=ERROR_USER_NOT_FOUND}

We were fetching some useful information ("/metadata/*") from Realtime Database before user logged (essentially auth is empty). Our database rules allow it:

{
"rules": {

"metadata": {
".read": true,
".write": false
}

".read": "auth != null",
".write": "auth != null"
}

Though our database rules allow that access, Firebase was bent on authToken, perhaps due to the default 'auth != null' rule protecting all the others.

We resolved the issue now by fetching even the metadata after the signIn, and everything is just fine.

Hope someone finds this useful.

Firebase fetch data using .value observer is not working?

You should be looping over the returned dictionary [String : AnyObject] and then creating the the corresponding object instances.

ref.observe(.value) { (snapshot) in
if let data = snapshot.value as? [String : AnyObject] {
for objectData in data.values {
let obj = object()
obj.setValuesForKeys(objectData as! [String : AnyObject])
self.objarray.append(obj)
print("%%%%%%% \(obj.test)")
}
}
}

Most efficient way to fetch data from Firebase

It sounds like you currently remove your observers when the view disappears. At that point Firebase will remove the users data from its memory cache. So indeed when you re-attach the listener in viewWillAppear, the data will need to be reloaded from the Firebase servers.

If you don't want the data to be reloaded, you'll need to make sure that it remains available on the device. There are two options for this:

  1. Ensure the data stays in memory
  2. Ensure the data is persisted to disk

Ensure the data stays in memory

To ensure the data stays in memory, you must keep the observer attached even after the user navigates away from the view. This means that you'll want another class to manage the observer, one that doesn't remove the observer when the user navigates.

The simplest approach for this is to have a global singleton that manages the observers and the user data, e.g. UserDataManager. When your view first calls this class, create/attach the listener and read the user data. When a subsequent view needs the users, they'll already be loaded in the UserDataManager ready for use.

The main problem with this is that as you do this for more data, you may end up keeping more data in memory than needed. So be aware of memory consumption of such unneeded data, and prune (remove listeners) as needed.

Ensure the data is persisted to disk

A simple way to reduce the amount of data that is downloaded is to =enable disk persistence](https://firebase.google.com/docs/database/ios/offline-capabilities#section-disk-persistence) when the app starts.

If disk persistence is enabled, the Firebase client stores data that it recently observed to disk (in addition to keeping any active data in memory). When you attach a new observer and the data isn't in memory yet, Firebase will check the disk cache for that data. If the data exists in the disk cache, it uses that to rebuild its memory cache and performs a much cheaper (bandwidth wise) check against the server.



Related Topics



Leave a reply



Submit