【问题标题】:my code not execute in the right order, my array is alway empty我的代码没有按正确的顺序执行,我的数组总是空的
【发布时间】:2020-08-02 15:06:56
【问题描述】:

我正在尝试运行我的函数,以便从 firebase cloud firestore 下载一些实时数据库数据更改。

问题是我的闭包 onSuccess 触发得早,闭包中的数组总是空的。

如何处理执行顺序,以便仅在 forEach() 之后成功执行闭包

在线阅读后,我想出了一些队列,但我不确定我是否正确使用。

在我的代码下面:

func getuserConfirmFriend(userLoggato: UserModel, onSuccess: @escaping([UserModel]) -> Void, onError: @escaping(_ errorMessage: String) -> Void, newPendingUser: @escaping(UserModel) -> Void, userRemoved: @escaping(UserModel) -> Void , listener: @escaping(_ listenerHandle: ListenerRegistration) -> Void){
        let queue = OperationQueue()
        let listenerRegistration = db.collection("user").document(userLoggato.userID).collection("confirmFriend").addSnapshotListener(includeMetadataChanges: true) { documentSnapshot, error in
            var userConfirmFriendsArray = [UserModel]()
            guard let snapshot = documentSnapshot else { return }
            
            let operation1 = BlockOperation {
                
                snapshot.documentChanges.forEach { (documentChange) in
                    switch documentChange.type {
                    case .added :
                        let dict = documentChange.document.data()
                        let name = dict["name"] as? String ?? "na name"
                        let surname = dict["surname"] as? String ?? "na name"
                        let email = dict["email"] as? String ?? "na name"
                        let userLevel = dict["adminLevel"] as? String ?? "unable to get admin level"
                        let idUser = dict["userID"] as? String ?? "no ID"
                        let position1 = dict["position"] as? String ?? "na preferance position"
                        let position2 = dict["position2"] as? String ?? "na preferance position"
                        let vote = dict["vote"] as? Int ?? 0
                        self.downloadImageForAdmin(userID: idUser) { (urlImage) in
                            let utente = UserModel(name: name, surname: surname, email: email, userID: idUser, adminLevel: userLevel, immagine: urlImage, position: position1, position2: position2, vote: vote)
                            
                            newPendingUser(utente)
                            userConfirmFriendsArray.append(utente)
                            //                           onSuccess(userConfirmFriendsArray)
                        }
                        print("CONFIRM User Added")
                    case .modified :
                        //implements action (new escaping)
                        
                        print("CONFIRM User Modified ")
                    case .removed :
                        print("CONFIRM User Removed")
                        let dict = documentChange.document.data()
                        let name = dict["name"] as? String ?? "na name"
                        let surname = dict["surname"] as? String ?? "na name"
                        let email = dict["email"] as? String ?? "na name"
                        let userLevel = dict["adminLevel"] as? String ?? "unable to get admin level"
                        let idUser = dict["userID"] as? String ?? "no ID"
                        let position1 = dict["position"] as? String ?? "na preferance position"
                        let position2 = dict["position2"] as? String ?? "na preferance position"
                        let vote = dict["vote"] as? Int ?? 0
                        self.downloadImageForAdmin(userID: idUser) { (urlImage) in
                            let utente = UserModel(name: name, surname: surname, email: email, userID: idUser, adminLevel: userLevel, immagine: urlImage, position: position1, position2: position2, vote: vote)
                            userRemoved(utente)
                        }
                    }
                    
                    
                    
                }
            }
            let operation2 = BlockOperation{
                DispatchQueue.main.async {
                    
                onSuccess(userConfirmFriendsArray)
                }
            }
            
            queue.addOperation(operation1)
            queue.addOperation(operation2)
            

        }
              
           listener(listenerRegistration)
       }

我的问题是 userConfirmFriend 总是空的,即使代码先执行 operation1 然后 2

对调度队列不太熟悉。

谢谢

【问题讨论】:

  • 您需要获得熟悉调度队列。您的代码是异步的。如果您不知道这意味着什么,请找出答案;我在这里有一些关于它的文章:programmingios.net/what-asynchronous-means 要在继续调用完成处理程序之前完成循环的所有迭代,您需要一个 调度组。这已经在 Stack Overflow 上解释过很多很多次了。 (我提到“很多”吗?)请在再次询问之前搜索。谢谢。
  • 这能回答你的问题吗? Returning data from async call in Swift function

标签: arrays swift multithreading firebase google-cloud-firestore


【解决方案1】:

您的问题出在开关盒.added 下forEach 循环内的self.downloadImageForAdmin 调用上。由于下载是异步的,forEach 循环操作通常会在下载完成之前完成,并且您的数组为空,因为您只有 append 回调数组。

解决此问题的方法是使用DispatchGroup (Apple Documentation)(下面的代码未经测试,但应该让您了解在这种情况下如何使用DispatchGroup)。

func getuserConfirmFriend(userLoggato: UserModel, onSuccess: @escaping([UserModel]) -> Void, onError: @escaping(_ errorMessage: String) -> Void, newPendingUser: @escaping(UserModel) -> Void, userRemoved: @escaping(UserModel) -> Void , listener: @escaping(_ listenerHandle: ListenerRegistration) -> Void)
{
    let dispatchGroup = DispatchGroup()
    let listenerRegistration = db.collection("user").document(userLoggato.userID).collection("confirmFriend").addSnapshotListener(includeMetadataChanges: true) { documentSnapshot, error in
        var userConfirmFriendsArray = [UserModel]()
        guard let snapshot = documentSnapshot else { return }

            snapshot.documentChanges.forEach { (documentChange) in
            switch documentChange.type {
                case .added :
                    let dict = documentChange.document.data()
                    let name = dict["name"] as? String ?? "na name"
                    let surname = dict["surname"] as? String ?? "na name"
                    let email = dict["email"] as? String ?? "na name"
                    let userLevel = dict["adminLevel"] as? String ?? "unable to get admin level"
                    let idUser = dict["userID"] as? String ?? "no ID"
                    let position1 = dict["position"] as? String ?? "na preferance position"
                    let position2 = dict["position2"] as? String ?? "na preferance position"
                    let vote = dict["vote"] as? Int ?? 0
                    dispatchGroup.enter()
                    self.downloadImageForAdmin(userID: idUser) { (urlImage) in
                        let utente = UserModel(name: name, surname: surname, email: email, userID: idUser, adminLevel: userLevel, immagine: urlImage, position: position1, position2: position2, vote: vote)
                        
                        newPendingUser(utente)
                        userConfirmFriendsArray.append(utente)
                        dispatchGroup.leave()
                    }
                    print("CONFIRM User Added")
                case .modified :
                    //implements action (new escaping)

                    print("CONFIRM User Modified ")
                case .removed :
                    print("CONFIRM User Removed")
                    let dict = documentChange.document.data()
                    let name = dict["name"] as? String ?? "na name"
                    let surname = dict["surname"] as? String ?? "na name"
                    let email = dict["email"] as? String ?? "na name"
                    let userLevel = dict["adminLevel"] as? String ?? "unable to get admin level"
                    let idUser = dict["userID"] as? String ?? "no ID"
                    let position1 = dict["position"] as? String ?? "na preferance position"
                    let position2 = dict["position2"] as? String ?? "na preferance position"
                    let vote = dict["vote"] as? Int ?? 0
                    self.downloadImageForAdmin(userID: idUser) { (urlImage) in
                        let utente = UserModel(name: name, surname: surname, email: email, userID: idUser, adminLevel: userLevel, immagine: urlImage, position: position1, position2: position2, vote: vote)
                        userRemoved(utente)
                    }
            }
        }
        dispatchGroup.notify(queue: .main) {
            onSuccess(userConfirmFriendsArray)
        }
    }
    listener(listenerRegistration)
}

DispatchGroup enter() 将一个块添加到组中,leave() 表示该块已完成。一旦添加到DispatchGroup 的所有块都完成后,就会调用notify()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    相关资源
    最近更新 更多