循环的快速完成处理程序将执行一次,而不是由于循环而执行10次

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了循环的快速完成处理程序将执行一次,而不是由于循环而执行10次相关的知识,希望对你有一定的参考价值。

我有一个带有Firestore查询的循环,该循环重复了10次。我需要在所有10个查询完成后调用(completion:block);在这里,我有我的代码,这样它就可以对每个查询执行(“完成:阻止”操作),但是这在服务器和用户的电话上会很繁重。我如何在下面进行更改以完成我刚刚描述的内容?

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: $0.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。您可以在每次调用异步代码时进入调度组,然后在每次完成后离开。然后,当一切完成后,它将调用notify块,您可以调用您的处理程序。这是一个简短的示例:

let dispatchGroup = DispatchGroup()
let array = []

for i in array {
    dispatchGroup.enter()
    somethingAsync() {
        dispatchGroup.leave()
    }
}

dispatchGroup.notify(queue: .main) {
    handler()
}

以上是关于循环的快速完成处理程序将执行一次,而不是由于循环而执行10次的主要内容,如果未能解决你的问题,请参考以下文章

如何将多处理用于函数而不是循环?

暂停一个while循环,而不是我在Python中的其余程序

break和continue的区别是啥?

Arduino Uno 压电扬声器循环而不是播放一次(编程新手)

windows程序消息循环机制

java 使用mysql怎么做到循环之后数据一次提交?