Swift Completion Handler Для L oop выполняется один раз вместо 10 раз из-за цикла - PullRequest
1 голос
/ 12 апреля 2020

II имеет oop с запросом в пожарном депо, который повторяется 10 раз. Мне нужно вызвать (завершение: блок) после того, как все 10 запросов завершены; Здесь у меня есть мой код, так что он выполняет (завершение: блок) для запроса, но это будет слишком тяжело для сервера и телефона пользователя. Как я могу изменить ниже, чтобы завершить sh, что я только что описал?

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)
                }
            }
        }

    }

, как вы можете видеть в самом конце, я зацикливаюсь 10 раз для этого запроса из-за for _ in 0 ..< 10:

if productId != "" {
                    db.collection(DatabaseRef.products).whereField(DatabaseRef.id, isEqualTo: productId).getDocuments(completion: block)
                }

Так что мне нужно сделать обработчик completion: block быть вызванным только один раз вместо 10 раз здесь.

1 Ответ

1 голос
/ 13 апреля 2020

Используйте DispatchGroup . Вы можете вводить группу отправки каждый раз, когда вызываете асинхронный код c, а затем выходить каждый раз, когда это делается. Затем, когда все закончится, он вызовет блок уведомлений, и вы можете вызвать ваш обработчик. Вот быстрый пример того, как это будет выглядеть:

let dispatchGroup = DispatchGroup()
let array = []

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

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