мой код не выполняется в правильном порядке, мой массив всегда пуст - PullRequest
1 голос
/ 02 августа 2020

Я пытаюсь запустить свою функцию, чтобы загрузить некоторые изменения данных базы данных в реальном времени из облачного хранилища firebase.

проблема заключается в том, что мое закрытие 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 всегда пуст, даже если код выполняет сначала операцию 1, а затем 2

не очень знаком с очередью на отправку

спасибо

1 Ответ

0 голосов
/ 02 августа 2020

Ваша проблема связана с вызовом self.downloadImageForAdmin в рамках forEach l oop под переключателем .added. Поскольку загрузка является асинхронной c, операция forEach l oop обычно завершается до завершения загрузки и оставляет ваш массив пустым, поскольку вы только 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().

...