Swift 由于循环,循环的完成处理程序将执行一次而不是 10 次
Swift Completion Handler For Loop to be performed once instead of 10 times due to the loop
我有一个循环,其中包含一个重复 10 次的 firestore 查询。在所有 10 个查询完成后,我需要调用 (completion: block);在这里,我有我的代码,以便它对每个查询执行 (completion: block),但这对服务器和用户的 phone 来说太重了。我怎样才能改变下面来完成我刚才描述的?
static func getSearchedProducts(fetchingNumberToStart: Int, sortedProducts: [Int : [String : Int]], handler: @escaping (_ products: [Product], _ lastFetchedNumber: Int?) -> Void) {
var lastFetchedNumber:Int = 0
var searchedProducts:[Product] = []
let db = Firestore.firestore()
let block : FIRQuerySnapshotBlock = ({ (snap, error) in
guard error == nil, let snapshot = snap else {
debugPrint(error?.localizedDescription)
return
}
var products = snapshot.documents.map { Product(data: [=11=].data()) }
if !UserService.current.isGuest {
db.collection(DatabaseRef.Users).document(Auth.auth().currentUser?.uid ?? "").collection(DatabaseRef.Cart).getDocuments { (cartSnapshot, error) in
guard error == nil, let cartSnapshot = cartSnapshot else {
return
}
cartSnapshot.documents.forEach { document in
var product = Product(data: document.data())
guard let index = products.firstIndex(of: product) else { return }
let cartCount: Int = document.exists ? document.get(DatabaseRef.cartCount) as? Int ?? 0 : 0
product.cartCount = cartCount
products[index] = product
}
handler(products, lastFetchedNumber)
}
}
else {
handler(products, lastFetchedNumber)
}
})
if lastFetchedNumber == fetchingNumberToStart {
for _ in 0 ..< 10 {
//change the fetching number each time in the loop
lastFetchedNumber = lastFetchedNumber + 1
let productId = sortedProducts[lastFetchedNumber]?.keys.first ?? ""
if productId != "" {
db.collection(DatabaseRef.products).whereField(DatabaseRef.id, isEqualTo: productId).getDocuments(completion: block)
}
}
}
}
正如你在最后看到的那样,由于 for _ in 0 ..< 10
,我为此查询循环了 10 次:
if productId != "" {
db.collection(DatabaseRef.products).whereField(DatabaseRef.id, isEqualTo: productId).getDocuments(completion: block)
}
所以我需要让 completion: block
处理程序在这里只被调用一次而不是 10 次。
使用 DispatchGroup。您可以在每次调用异步代码时进入调度组,然后在每次完成时离开。然后,当一切都完成后,它将调用通知块,您可以调用您的处理程序。这是一个简单的示例:
let dispatchGroup = DispatchGroup()
let array = []
for i in array {
dispatchGroup.enter()
somethingAsync() {
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
handler()
}
我有一个循环,其中包含一个重复 10 次的 firestore 查询。在所有 10 个查询完成后,我需要调用 (completion: block);在这里,我有我的代码,以便它对每个查询执行 (completion: block),但这对服务器和用户的 phone 来说太重了。我怎样才能改变下面来完成我刚才描述的?
static func getSearchedProducts(fetchingNumberToStart: Int, sortedProducts: [Int : [String : Int]], handler: @escaping (_ products: [Product], _ lastFetchedNumber: Int?) -> Void) {
var lastFetchedNumber:Int = 0
var searchedProducts:[Product] = []
let db = Firestore.firestore()
let block : FIRQuerySnapshotBlock = ({ (snap, error) in
guard error == nil, let snapshot = snap else {
debugPrint(error?.localizedDescription)
return
}
var products = snapshot.documents.map { Product(data: [=11=].data()) }
if !UserService.current.isGuest {
db.collection(DatabaseRef.Users).document(Auth.auth().currentUser?.uid ?? "").collection(DatabaseRef.Cart).getDocuments { (cartSnapshot, error) in
guard error == nil, let cartSnapshot = cartSnapshot else {
return
}
cartSnapshot.documents.forEach { document in
var product = Product(data: document.data())
guard let index = products.firstIndex(of: product) else { return }
let cartCount: Int = document.exists ? document.get(DatabaseRef.cartCount) as? Int ?? 0 : 0
product.cartCount = cartCount
products[index] = product
}
handler(products, lastFetchedNumber)
}
}
else {
handler(products, lastFetchedNumber)
}
})
if lastFetchedNumber == fetchingNumberToStart {
for _ in 0 ..< 10 {
//change the fetching number each time in the loop
lastFetchedNumber = lastFetchedNumber + 1
let productId = sortedProducts[lastFetchedNumber]?.keys.first ?? ""
if productId != "" {
db.collection(DatabaseRef.products).whereField(DatabaseRef.id, isEqualTo: productId).getDocuments(completion: block)
}
}
}
}
正如你在最后看到的那样,由于 for _ in 0 ..< 10
,我为此查询循环了 10 次:
if productId != "" {
db.collection(DatabaseRef.products).whereField(DatabaseRef.id, isEqualTo: productId).getDocuments(completion: block)
}
所以我需要让 completion: block
处理程序在这里只被调用一次而不是 10 次。
使用 DispatchGroup。您可以在每次调用异步代码时进入调度组,然后在每次完成时离开。然后,当一切都完成后,它将调用通知块,您可以调用您的处理程序。这是一个简单的示例:
let dispatchGroup = DispatchGroup()
let array = []
for i in array {
dispatchGroup.enter()
somethingAsync() {
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
handler()
}