我的第一个使用Firebase的大应用程序刚刚启动,我遇到了一个问题 - 我很快就没有下载带宽了。
我已经研究了几种缓存数据的选项。我希望缓存数据仅在当前时使用。如果自创建缓存后Firebase上的数据已更新,我想重新下载所有数据。
我不希望在会话中多次更新数据。所以我想在获取新数据后立即删除观察者。
我尝试了两件事,但我不完全确定它们是如何工作的。
FIRDatabase.database().persistenceEnabled = true
启用持久性非常好,因为只需一行代码就可以缓存从Firebase下载的所有内容。即使应用程序未连接到互联网,它也会提取缓存数据并正常开展业务。
但我的问题是:当Firebase上的数据更新时,缓存会更新吗?看来事实并非如此。
当我进入并更改Firebase上的值并重新启动应用时,它只会给我缓存的值,而不是更新的值。
那么我试试这个:
ref.keepSynced(true)
这似乎有效。当我重新启动应用程序时,我会获得更新的值。
但接下来我的问题是:应用程序每次启动时都会下载数据(我不想要这个)或者只是需要更新时才会下载数据?
答案 0 :(得分:1)
好问题!在我们的上一个应用程序中使用persistenceEnabled = true
时,我和我的团队遇到了吨的问题(即我们不断从云端接收过时的数据)。我们甚至制作了一个简单的命令行标志,通过Xcode中的 Run 会话禁用它(又名脏黑客!)。
更完整的解决方案是使用您提到的FIRDatabaseReference.keepSynced(_:)
API。再看一下这些文档似乎会按预期工作:
通过在某个位置调用
keepSynced(true)
,该位置的数据将自动下载并保持同步,即使没有为该位置附加侦听器也是如此。此外,虽然位置保持同步,但不会从持久性磁盘缓存中逐出。
但是,对于大型数据集,我建议不在根节点上启用此行为 - 仅限于特定的子树!
答案 1 :(得分:1)
只要数据库中的某个位置存在活动侦听器,并且只有当该位置下的任何数据发生更改时,您的应用才会同步Firebase实时数据库中的数据。当您使用keepSynced时,您实际上是在引用的位置附加一个侦听器。
当您的应用程序进程停止时,将有效删除所有侦听器。当您的应用程序进程再次启动时,没有任何旧的侦听器再次附加。您必须执行代码才能获得新的侦听器。如果未附加新侦听器,则不会同步新数据。换句话说,keepSynced不会在应用程序调用之间的位置建立持久同步。你必须每次都要求它。
启用持久性只是允许侦听器立即响应缓存数据,而无需等待来自服务的数据。监听器将首先接收缓存的数据,然后在此之后进行后续更新,只要它仍然附加并且服务上的数据实际上正在发生变化。
答案 2 :(得分:1)
我设法让应用程序做我想做的事情,虽然它可能不是最优雅的方式。
1。)我在persistenceEnabled
中致电didFinishLaunchingWithOptions
。这会缓存从Firebase检索到的所有数据,以便在下次应用启动时立即使用。
2.)我不要在数据库引用上调用keepSynced
。否则应用程序会在每次加载应用程序时下载所有数据(不是我想要的)。
3。)如果有新数据,则处理两次 - 一次处理缓存数据,然后处理器检测到新数据一次。在第二次处理数据后,我删除了观察者。我使用计数器来判断它是第一次还是第二次处理数据。
4。)如果没有新数据,则只处理一次,不下载任何内容。
这有效地允许我仅在设备上缓存的数据过期时才下载数据。否则使用缓存的数据。
以下是一些要演示的代码:
// First download is cached data, second one is updated live data if there is updated data on Firebase
var timesDownloaded = 0
func downloadPops(andOnCompletion completion:@escaping ()->()){
let baseRef = FIRDatabase.database().reference().child("SomeChild")
baseRef.observe(.value, with: { snapshot in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
self.timesDownloaded+=1
// Handle the data
}
// First download is cached data, second one is updated live data if there is updated data on Firebase
if self.timesDownloaded > 1 {
print("Showing updated data")
baseRef.removeAllObservers()
} else {
print("Showing cached data")
}
completion()
})
}