Swift for 循环不等待 firestore 调用完成
Swift for loop not waiting for firestore call to complete
我知道 firestore 调用是异步的,这意味着这行不通:
private func removeUserSavedMomentFromAllUsers(moment: StoryMoment, completion: @escaping () -> Void) {
guard let savedByUIDs = moment.savedByUIDs else { return }
guard let momentID = moment.id else { return }
for id in savedByUIDs {
self.userInfoCollection.document(id).collection("savedMedias").document(momentID).delete { error in
if let error = error {
print("Error removing user saved moment from UID: \(error)")
}
}
}
}
因为循环将在删除调用完成之前继续(与获取请求相同)。我过去曾使用调度组来解决这个问题。这是一个工作示例:
private func removeUserSavedMomentFromAllUsers(moment: StoryMoment, completion: @escaping () -> Void) {
guard let savedByUIDs = moment.savedByUIDs else { return }
guard let momentID = moment.id else { return }
let disSemaphore = DispatchSemaphore(value: 0)
let dispatchQueue = DispatchQueue(label: "group 1")
dispatchQueue.async {
for id in savedByUIDs {
self.userInfoCollection.document(id).collection("savedMedias").document(momentID).delete { error in
if let error = error {
print("Error removing user saved moment from UID: \(error)")
} else {
disSemaphore.signal()
}
}
disSemaphore.wait()
}
}
}
但是那些在后台线程上完成所有工作。
我的问题是:如何在调用 firebase docs 的 for 循环中使用 async/await?
问题第一部分中的代码确实有效 - 并且适用于一小部分数据。但是,通常建议不要在紧密循环中调用 Firebase 函数。
虽然问题提到了 DispatchQueues,但我们将 DispatchGroups 与 .enter 和 .leave 一起使用,因为它非常干净。
给定一个 Firebase 结构
sample_data
a
key: "value"
b
key: "value"
c
key: "value"
d
key: "value"
e
key: "value"
f
key: "value"
假设我们要删除 d、e 和 f 文档。这是代码
func dispatchGroupDelete() {
let documentsToDelete = ["d", "e", "f"]
let collection = self.db.collection("sample_data") //self.db points to my Firestore
let group = DispatchGroup()
for docId in documentsToDelete {
group.enter()
let docToDelete = collection.document(docId)
docToDelete.delete()
group.leave()
}
}
虽然此答案不使用 async/await,但此用例可能不需要这些
如果你想使用 async/await 你试试这样做
let documentsToDelete = ["d", "e", "f"]
let collection = self.db.collection("sample_data")
for docId in documentsToDelete {
let docToDelete = collection.document(docId)
Task {
do {
try await docToDelete.delete()
} catch {
print("oops")
}
}
}
我知道 firestore 调用是异步的,这意味着这行不通:
private func removeUserSavedMomentFromAllUsers(moment: StoryMoment, completion: @escaping () -> Void) {
guard let savedByUIDs = moment.savedByUIDs else { return }
guard let momentID = moment.id else { return }
for id in savedByUIDs {
self.userInfoCollection.document(id).collection("savedMedias").document(momentID).delete { error in
if let error = error {
print("Error removing user saved moment from UID: \(error)")
}
}
}
}
因为循环将在删除调用完成之前继续(与获取请求相同)。我过去曾使用调度组来解决这个问题。这是一个工作示例:
private func removeUserSavedMomentFromAllUsers(moment: StoryMoment, completion: @escaping () -> Void) {
guard let savedByUIDs = moment.savedByUIDs else { return }
guard let momentID = moment.id else { return }
let disSemaphore = DispatchSemaphore(value: 0)
let dispatchQueue = DispatchQueue(label: "group 1")
dispatchQueue.async {
for id in savedByUIDs {
self.userInfoCollection.document(id).collection("savedMedias").document(momentID).delete { error in
if let error = error {
print("Error removing user saved moment from UID: \(error)")
} else {
disSemaphore.signal()
}
}
disSemaphore.wait()
}
}
}
但是那些在后台线程上完成所有工作。 我的问题是:如何在调用 firebase docs 的 for 循环中使用 async/await?
问题第一部分中的代码确实有效 - 并且适用于一小部分数据。但是,通常建议不要在紧密循环中调用 Firebase 函数。
虽然问题提到了 DispatchQueues,但我们将 DispatchGroups 与 .enter 和 .leave 一起使用,因为它非常干净。
给定一个 Firebase 结构
sample_data
a
key: "value"
b
key: "value"
c
key: "value"
d
key: "value"
e
key: "value"
f
key: "value"
假设我们要删除 d、e 和 f 文档。这是代码
func dispatchGroupDelete() {
let documentsToDelete = ["d", "e", "f"]
let collection = self.db.collection("sample_data") //self.db points to my Firestore
let group = DispatchGroup()
for docId in documentsToDelete {
group.enter()
let docToDelete = collection.document(docId)
docToDelete.delete()
group.leave()
}
}
虽然此答案不使用 async/await,但此用例可能不需要这些
如果你想使用 async/await 你试试这样做
let documentsToDelete = ["d", "e", "f"]
let collection = self.db.collection("sample_data")
for docId in documentsToDelete {
let docToDelete = collection.document(docId)
Task {
do {
try await docToDelete.delete()
} catch {
print("oops")
}
}
}