iOS Firestore IsPersistenceEnabled does not disable existing cached listener results

Viewed 438

The cache routinely fulfills our first FireStore snapshot listener results, almost always with out-of-date data (obviously). The listener often fires again with the missing results immediately after.

Using FireStore settings to set isPersistenceEnabled to false does not stop cache results from returning. Do I have to clear the cache that has already been built?

When checking snap.metadata.isFromCache, the cache is clearly still operating.

Disabling persistence while the VC is being embedded in present does nothing (Container View):

vc?.db = Firestore.firestore()
let settings = FirestoreSettings()
settings.isPersistenceEnabled = false
vc?.db?.settings = settings

Some code:

var isFirstQuery = true
queuesInLocationRef?.remove()
queuesInLocationRef = db?.collection("location").whereField("city", isEqualTo: city).whereField("region", isEqualTo: region).addSnapshotListener({ (snapshot, error) in
    guard let snap = snapshot else {
         print("watch location err: ", error!)
         return
    }
    self.processDocumentChanges(documentChanges: snap.documentChanges, isFirstQuery: isFirstQuery)
    isFirstQuery = false
})

I have important things to do the first time the listener fires. When I have an internet connection, this will often fire with stale cached results first, which I want to exclude. I have tried checking isFromCache and early returning, but have found that even with a network connection, up-to-date results may come back as from the cache. This results in the listener not firing again.

If cached results never came back, it would be smooth sailing. I am not sure what disabling persistence does in the iOS SDK but it does not help here.

2 Answers

What you're describing is addressed by telling the SDK to deliver events for metadata changes. Be sure to read that documentation thoroughly.

When you register for metadata changes, your callback will be invoked when something in the metadata changes, including the source of the data (even if the document data didn't change at all). This is how you can check if the data is definitely up to date from the server - snapshot.metadata.isFromCache should return false.

To ask for metadata changes, call addSnapshotListener like this:

query.addSnapshotListener(includeMetadataChanges: true) { documentSnapshot, error in
    // ...
}

You can either limit the amount of memory available to Firestore's global cache or discard cached results on a per-return basis. It sounds like you just want to ignore cached results, so just ignore them:

guard let cached = snapshot?.metadata.isFromCache,
    !cached, // only pass guard when false
    let snapshot = snapshot else {
        return
}

// handle results

This is the same as writing:

if let cached = snapshot?.metadata.isFromCache,
    cached == false {
    // handle results
}
Related