1

Seems like a simple question, but if I call:

query.observeSingleEvent(of: .value ...

then I always get data that's been persisted locally. The only way to get around this (that I've found) is to set up an observer that continues observing indefinitely.

For example, say I have an app where I'm viewing a user's profile. That user's data gets persisted locally. I come back ten days later to the same profile. That user has changed his name (or something). I only need to observe a single event, but that single event will give me the cached data (which is now out-of-date). I don't want to set up a continuous observer for every user profile I visit, because that will cause unnecessary updates (say I never come back to this profile again).

Anyway, I hope this question is clear. Would appreciate any insights.

EDIT:

What I ended up doing as a workaround is to simply call observe(.value) and let it respond twice. The first response is from the cache; the second from the server. This helps in cases where you're not guaranteed to have a connection as soon as you make the request.

joelg
  • 1,094
  • 9
  • 19
  • Using `observeSingleEvent` doesn't combine well with using disk persistence. Use one or the other, not both. See my answer here: https://stackoverflow.com/questions/34486417/firebase-offline-capabilities-and-addlistenerforsinglevalueevent While the question was about Android, the exact same applies to the iOS SDK. – Frank van Puffelen Jun 30 '17 at 17:39
  • Frank, there is a bit of an oversight with not being allowed to query the server directly, even when persisting. For instance, if I get a push notification that wants to tell about something on the server, and I want it as soon as the app launches (after tapping the push notification), I have to wait for a listener to tell me that is has the data I'm looking for. Really a strange way to do it. @FrankvanPuffelen – joelg Aug 02 '17 at 18:48

2 Answers2

1

From what I understand, you want to retrieve fresh data with observeSingleEvent. You can attach keepSynced to do so:

    let query = FIRDatabase.database().reference().child("item")

    query.keepSynced(true)

    query.observeSingleEvent(of: .value ... 

EDIT

ObserveSingleEventType with keepSycned will not work if the Firebase connection cannot be established on time. This is especially true during appLaunch or in the appDelegate where there is a delay in the Firebase connection and the cached result is given instead. It will also not work at times if persistence is enabled and observeSingleEvent might give the cached data first. In situations like these, a continuos ObserveEventType is preferred and should be used if you absolutely need fresh data.

gwinyai
  • 2,560
  • 2
  • 15
  • 17
  • This actually isn't correct. Calling keepSynced does nothing other than attach a listener to that query, which will then keep the latest in memory. But I need the latest "now," meaning as soon as observeSingleEvent is called. – joelg Aug 02 '17 at 18:47
  • keepSynced does not attach a listener as you are implying, it forces a query to Firebase to look for the latest data to download, if and only if it can make a connection. So your question seems unclear. If you look through Frank's link to his solution in the comments, it is consistent with mine and explains how to modify observeSingleEvent to get the latest values with keepSynced. If you found a solution, would you post it to make it clear to others who might view this and wonder why keepSynced never worked for you. – gwinyai Aug 03 '17 at 17:23
  • "it is consistent with mine and explains how to modify observeSingleEvent to get the latest values with keepSynced". Where do you see this, exactly? – joelg Aug 03 '17 at 18:40
  • https://stackoverflow.com/questions/34486417/firebase-offline-capabilities-and-addlistenerforsinglevalueevent under the title "Solution and Workaround" in the last paragraph. – gwinyai Aug 03 '17 at 20:07
  • To paraphrase what is said there, "As a workaround you can also call keepSynced(true) on the locations where you use a single-value event listener. This ensures that the data is updated whenever it changes, which drastically improves the chance that your single-value event listener will see the current value." This seems to fit your question, does it not? – gwinyai Aug 03 '17 at 20:11
  • Kind of, but it's not a solution. If you call keepSynced(true) on a location, then yes, it does "improve the chance that your single-value event listener will see the current value", but it's no guarantee. For example, if I launch the app due to a push notification, request data via a single-value event listener, the callback may OR may not have the latest data I need. If the data was created on the server while the app was listening, then yes, it will have the data. If the app had been terminated, it may not have yet had time to listen to get the latest values. – joelg Aug 04 '17 at 13:14
  • BTW, my question isn't flawed. Not sure why you down-voted it. – joelg Aug 04 '17 at 13:14
  • Well yes, it is already well known keepSynced fails for observeSingleEvent in environments like app launch or appDelegate which is where I assume you are handling the push notification but your question suggests a use case outside this when you said, "I have an app where I'm viewing a user's profile". The reason keepSynced fails at app launch is because the Firebase connection is not immediately available and there is a work around but no one can suggest this if your example is very different from your actual use case. KeepSynced does work but it depends on when you are using it. – gwinyai Aug 04 '17 at 15:31
  • Crap, you're totally right. The nature of the question changed over time I didn't bother respecting the original post. I'll mark your answer as accepted and start a new one about push notifications (handled in the app's delegate). Does that seem reasonable, or should I just edit the current question? Thanks for your patience. – joelg Aug 05 '17 at 16:36
  • And I did come up with a workaround, but it's hacky. Essentially, I call observe(.value) and listen for two responses (the first, which is from the cache, and the second, which gives me what I need from the server). I'm sure there's a better way. – joelg Aug 05 '17 at 16:38
  • I feel that is reasonable and I am totally down with accepting the original post where the use case did not mention push notifications. I guess there's really no harm in asking for a more efficient workaround with a new question but I've always been of the opinion that if it works then it works. Your workaround sounds good though. – gwinyai Aug 05 '17 at 18:19
  • If you would edit your question a bit. I realize my down-vote is misplaced since I thought you were going off-topic. It's the only way to reverse the down-vote because it is currently locked. – gwinyai Aug 05 '17 at 20:52
  • Will do. Same goes for your answer. – joelg Aug 06 '17 at 22:19
0

In my case, Updating firebase iOS SDK to v5.4.0 from v4.11.0 solved problem.

sagaraya
  • 46
  • 2