如何获取异步 Firebase 数据读取的进度?
Posted
技术标签:
【中文标题】如何获取异步 Firebase 数据读取的进度?【英文标题】:How to get progress of asynchronous Firebase data read? 【发布时间】:2021-07-27 22:50:18 【问题描述】:我有一些代码可以在自定义加载屏幕上从 Firebase 读取数据,我只想在读取集合中的所有数据后进行 segue(我事先知道不会超过 10 或 15 个数据要阅读的条目,我正在检查以确保用户有互联网连接)。我有一个我想实现的加载动画,它通过调用activityIndicatorView.startAnimating() 开始并通过调用activityIndicatorView.stopAnimating() 停止。我不确定在哪里放置这些或与数据检索功能相关的执行 segue 功能。任何帮助表示赞赏!
let db = Firestore.firestore()
db.collection("Packages").getDocuments(snapshot, error) in
if error != nil
// DB error
else
for doc in snapshot!.documents
self.packageIDS.append(doc.documentID)
self.packageNames.append(doc.get("title") as! String)
self.packageIMGIDS.append(doc.get("imgID") as! String)
self.packageRadii.append(doc.get("radius") as! String)
【问题讨论】:
使用完成块。 我没用过,能详细点吗? Firebase 是异步的 - 这意味着数据从 Firebase 服务器到达需要时间。 Firebase 函数使用 closures - 这是调用后的括号 中的部分。 Firebase 数据在在该闭包内有效,因此如果您想在 Firebase 数据到达后采取行动,那就是这样做的地方。请记住,FIrebase 速度非常快——即使是大型数据集,所以您可能不需要该进度指示器,因为它不会显示足够长的时间以产生任何影响。 (一般来说) 知道了,感谢您的见解! 【参考方案1】:您不需要知道读取的进度,只需知道读取的开始时间和完成时间,以便您可以启动和停止活动视图。
当您调用 getDocuments
时开始读取。
在getDocuments
完成闭包中的for
循环之后读取完成。
所以:
let db = Firestore.firestore()
activityIndicatorView.startAnimating()
db.collection("Packages").getDocuments(snapshot, error) in
if error != nil
// DB error
else
for doc in snapshot!.documents
self.packageIDS.append(doc.documentID)
self.packageNames.append(doc.get("title") as! String)
self.packageIMGIDS.append(doc.get("imgID") as! String)
self.packageRadii.append(doc.get("radius") as! String)
DispatchQueue.main.async
activityIndicatorView.stopAnimating()
就风格而言,拥有多个关联数据的数组有点代码味道。相反,您应该创建一个具有相关属性的struct
,并创建该结构的单个实例数组。
您还应该避免强制展开。
struct PackageInfo
let id: String
let name: String
let imageId: String
let radius: String
...
var packages:[PackageInfo] = []
...
db.collection("Packages").getDocuments(snapshot, error) in
if error != nil
// DB error
else if let documents = snapshot?.documents
self.packages = documents.compactMap doc in
if let title = doc.get("title") as? String,
let imageId = doc.get("imgID") as? String,
let radius = doc.get("radius") as? String
return PackageInfo(id: doc.documentID, name: title, imageId: imageId, radius: radius)
else
return nil
【讨论】:
非常感谢,感谢您的额外提示!两个问题: 1. 由于 firebase 数据函数是异步的, DispatchQueue.main.async 如何“绕过”它? 2. 如何使用指定的 id (id: doc.documentID) 访问 PackageInfo 对象/结构? IE。如果我想为某个文档 ID 修改结构中的某些字段 [实时更新] 调度队列主异步不会绕过异步获取。它只是确保 UI 的更新(停止活动指示器)发生在主队列上,因为所有 UI 更新都必须在主队列上执行。获取完成后,闭包中的所有内容都会执行 好吧,您有文档 ID,因此您可以获取它并应用更新。另一种方法是将整个文档存储在结构中 这对调度队列很有意义,谢谢。关于包结构,对,但是我如何获取具有该 ID 的包?我是否需要手动搜索结构并记下该包 ID 匹配的索引,并使用该索引例如从数组中删除该包结构?我知道数组有 .indexOf() 和 .remove(at:),对于每个结构都与一个 id 相关联的结构数组,是否存在类似的前者? 我不知道你是如何使用数组的。如果您在 tableview 中显示数据,那么您通常知道您正在使用的索引。否则你可以搜索数组(效率不是很高)或使用 id:package 的字典。【参考方案2】:在单个读取操作中没有进度报告,无论是待处理还是已完成。
如果您想要更详细的报告,您可以自己implement pagination 了解您已经阅读了多少项目。如果您想根据总数显示进度,这意味着您还需要自己跟踪总数。
【讨论】:
如何检查读取操作是否已完成(这对我有用)? 当你的回调被调用时,读操作完成。因此,如果您只想隐藏动画,那将是一个不错的选择。以上是关于如何获取异步 Firebase 数据读取的进度?的主要内容,如果未能解决你的问题,请参考以下文章
如何在显示firebase数据获取的进度条时通过startListening()解决错误? [重复]
从firebase数据库获取数据到android应用程序时使用进度条