for 循环中的异步调用会触发两次完成

Asynchronous call in for loop fires two completions

我有一个检索数据的方法。此数据可以但 不必 包含图像。下面的方法是 按顺序 检索数据,这对应用程序至关重要:

    static func getWishes(dataSourceArray: [Wishlist], completion: @escaping (_ success: Bool, _ dataArray: [Wishlist]) -> Void){
    
    var dataSourceArrayWithWishes = dataSourceArray
    
    let db = Firestore.firestore()
    let userID = Auth.auth().currentUser!.uid
    var j = 0
    let dispatchSemaphore = DispatchSemaphore(value: 0)
    let dispatchSemaphoreOuter = DispatchSemaphore(value: 0)
    let dispatchQueue1 = DispatchQueue(label: "taskQueue")
    var listCounter = 0
    dispatchQueue1.async {
        for list in dataSourceArray {
            listCounter += 1
            db.collection("users").document(userID).collection("wishlists").document(list.name).collection("wünsche").order(by: "wishCounter").getDocuments() { ( querySnapshot, error) in
                
                if let error = error {
                    print(error.localizedDescription)
                    
                } else {
                    // dispatch group to make sure completion only fires when for loop is finished
                    // append every Wish to array at wishIDX
                    var i = 0
                    let dispatchQueue = DispatchQueue(label: "taskQueue1")
                    if (querySnapshot?.documents.count)! > 0 {

                        dispatchQueue.async {
                            for document in querySnapshot!.documents {
                                
                                let documentData = document.data()
                                let imageUrlString = document["imageUrl"] as? String ?? ""              
                                if let imageUrl = URL(string: imageUrlString) {
                                    KingfisherManager.shared.retrieveImage(with: imageUrl, options: nil, progressBlock: nil, completionHandler: { result in
                                        
                                        var image = UIImage()
                                        
                                        switch result {
                                        case .success(let abc):
                                            image = abc.image
                                            
                                        case .failure(let error):
                                            print(error)
                                            break
                                        }
                                        dataSourceArrayWithWishes[wishIDX].wishes.append(Wish(image: image))

                                        i = i + 1
                                        
                                        if i == querySnapshot?.documents.count {
                                            j = j + 1
                                            dispatchSemaphoreOuter.signal()
                                            dispatchSemaphore.signal()
                                            
                                            if j == dataSourceArray.count {
                                                print("completion1")
                                                completion(true, dataSourceArrayWithWishes)
                                            }
                                        } else {
                                            dispatchSemaphore.signal()
                                        }
                                    })
                                } else {
                                    dataSourceArrayWithWishes[wishIDX].wishes.append(Wish(image: image))
                                    
                                    i = i + 1
                                    
                                    if i == querySnapshot?.documents.count {
                                        j = j + 1
                                        dispatchSemaphoreOuter.signal()
                                        dispatchSemaphore.signal()
                                        
                                        if j == dataSourceArray.count {
                                            print("completion3")
                                            completion(true, dataSourceArrayWithWishes)
                                        }
                                    } else {
                                        dispatchSemaphore.signal()
                                    }
                                }
                                dispatchSemaphore.wait()
                            }
                        }
                    } else {
                        j = j + 1
                        dispatchSemaphoreOuter.signal()
                    }
                }
            }
            // without this code the function will not fire a completion if only a single empty list is in dataSourceArray
//                if listCounter == dataSourceArray.count {
//                    print("completion")
//                    completion(true, dataSourceArrayWithWishes)
//                }
//                continue
            }
        }
    }

如果 if (querySnapshot?.documents.count)! > 0true,此方法工作正常,但如果 dataSourceArray 只包含一个空的 list,它会失败,因为它永远不会触发 completion .我尝试用 listCounter 和底部的代码修复它。这种 类的 有效但不干净,因为它总是触发 2 completions 这在应用程序中看起来很奇怪。如果 dataSourceArray?

中只有一个空的 list,谁知道我该如何解决这个问题

我真的被困在这里了,所以我很高兴得到每一个帮助!

您忘记在 if (querySnapshot?.documents.count)! > 0

else 分支中调用完成处理程序

注意:正如其他评论者已经指出的那样,最好将您的代码拆分为多个函数以提高可读性和可维护性。

您可以将完成处理程序作为参数传递给这些函数。