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:
- Immediately raise events with any complete cached data.
- 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 aValue
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:
- Ensure the data stays in memory
- 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
How to Access All Images in a .Xcassets at Once
Nsmanagedobject Setter Giving Me [ Myobject Setname:]: Unrecognized Selector Sent to Instance
Media Query Not Working for iPhone and Ipad
Tabbarcontroller Adding Custom Button Not Clickable Issue
Xcode UI Tests Can't Find Views That Are Added Programmatically
Prepareforsegue Not Called from Custom UItableviewcell
Checking Cellular Network Type in iOS
How to Add Pagination in UItableview.
Parse Cloud - Livequeries - iOS Client Doesn't Work
Can't Write Non Current User Objects by Pfuser Currentuser
Media_Err_Decode on HTML5 Video in iOS UIwebview After Many Plays
Conversion from String to Date in Swift Returns Nil
Nsdateformatter Still Parsing Instead Having Incorrect Format
How to Upload Multiple Images in Multipart Using Alamofire
Dynamic Height for a Uitableview Based on a Dynamic Collection View