Свифт, Как заставить обработчик завершения работать так, как я хочу? - PullRequest
0 голосов
/ 10 апреля 2019

Я получаю информацию о пользователях из Firebase, и моя цель - получить группу пользователей и затем отображать их на экране по одному в стопке карт. Для этого я использую обработчик завершения. Однако мой код внутри обработчика завершения запускается до того, как завершится выборка всех пользователей.

Спасибо за любую помощь.

Вот мой код. Я хочу, чтобы "fetchOneUser ()" запускался, когда "fetchAllUsers" выполнен:

fetchAllUsers(completion: { message in
   print(message)
   print("FetchOneUser")
   self.fetchOneUser()
})

Вот функция fetchAllUser:

func fetchAllUsers(completion: @escaping (_ message: String) -> Void){
        //User or advertiser?
        Database.database().reference(withPath: "Advertiser").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in

            if snapshot.exists(){
                myAdvertiserVar.advertiser = true
                self.currentUserKind = "Advertiser"
                self.otherUserKind = "Users"
            }
            else{
                self.currentUserKind = "Users"
                self.otherUserKind = "Advertiser"
            }

            // Fetch
            let query = self.ref?.child(self.otherUserKind).queryOrdered(byChild: "email")
            query?.observeSingleEvent(of: .value) {
                (snapshot) in
                for child in snapshot.children.allObjects as! [DataSnapshot] {
                    let id = child.key
                    //If Already Accepted, don't fetch
                    Database.database().reference(withPath: self.currentUserKind).child(self.uid).child("Accepted").child(id).observeSingleEvent(of: .value, with: {(accepted) in
                        if accepted.exists(){
                            print("\(id) är redan Accepted")
                        }
                        else{
                            if myAdvertiserVar.advertiser == true{
                                let value = child.value as? NSDictionary
                                let username = value?["Username"] as? String
                                let occupation = value?["Occupation"] as? String
                                let age = value?["Age"] as? String
                                let bio = value?["Bio"] as? String
                                let email = value?["email"] as? String
                                let user = User(id: id, username: username, occupation: occupation, age: age, bio: bio, email: email)
                                self.usersArray.append(user)
                            }
                            else{
                                let value = child.value as? NSDictionary
                                let username = value?["Owner"] as? String
                                let occupation = value?["Location"] as? String
                                let age = value?["Rent"] as? String
                                let bio = value?["About"] as? String
                                let email = value?["email"] as? String
                                let user = User(id: id, username: username, occupation: occupation, age: age, bio: bio, email: email)
                                self.usersArray.append(user)
                            }
                        }
                    })
                }
                print(self.usersArray.count)
                completion("Users list fetched")
            }
        })
    }

Ответы [ 2 ]

2 голосов
/ 10 апреля 2019

Вам необходимо использовать DispatchGroup, поскольку внутренние вызовы асинхронны

func fetchAllUsers(completion: @escaping (_ message: String) -> Void){
    //User or advertiser?
    Database.database().reference(withPath: "Advertiser").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in

        if snapshot.exists(){
            myAdvertiserVar.advertiser = true
            self.currentUserKind = "Advertiser"
            self.otherUserKind = "Users"
        }
        else{
            self.currentUserKind = "Users"
            self.otherUserKind = "Advertiser"
        }

        // Fetch
        let query = self.ref?.child(self.otherUserKind).queryOrdered(byChild: "email")
        query?.observeSingleEvent(of: .value) {
            (snapshot) in

            let g = DispatchGroup()

            for child in snapshot.children.allObjects as! [DataSnapshot] {
                let id = child.key
                //If Already Accepted, don't fetch

                g.enter()

                Database.database().reference(withPath: self.currentUserKind).child(self.uid).child("Accepted").child(id).observeSingleEvent(of: .value, with: {(accepted) in
                    if accepted.exists(){
                        print("\(id) är redan Accepted")
                    }
                    else{
                        if myAdvertiserVar.advertiser == true{
                            let value = child.value as? NSDictionary
                            let username = value?["Username"] as? String
                            let occupation = value?["Occupation"] as? String
                            let age = value?["Age"] as? String
                            let bio = value?["Bio"] as? String
                            let email = value?["email"] as? String
                            let user = User(id: id, username: username, occupation: occupation, age: age, bio: bio, email: email)
                            self.usersArray.append(user)
                        }
                        else{
                            let value = child.value as? NSDictionary
                            let username = value?["Owner"] as? String
                            let occupation = value?["Location"] as? String
                            let age = value?["Rent"] as? String
                            let bio = value?["About"] as? String
                            let email = value?["email"] as? String
                            let user = User(id: id, username: username, occupation: occupation, age: age, bio: bio, email: email)
                            self.usersArray.append(user)
                        }
                    }

                    g.leave()
                })
            }


            g.notify(queue: .main, execute: {

                print(self.usersArray.count)
                completion("Users list fetched")

            })
        }
    })
}
1 голос
/ 10 апреля 2019

На основе Документация Firebase:

Firebase использует метод refrence(), чтобы получить ссылку на базу данных для корня вашей базы данных в реальном времени, асинхронную.

это означает, что для извлечения результата требуется больше времени, чем для цикла, в этой ситуации ваш цикл for завершает и вызывает блокировку завершения и выводит вас из метода, после чего возвращается результат вашего запроса.

ваш код должен выглядеть как

var firebaseDatabaseRefrence: DatabaseReference!

override func viewDidLoad() {
   super.viewDidLoad()
   Database.database().reference(withPath: self.currentUserKind)
}

func someMethod() {

  self.firebaseDatabaseRefrence
  .child(self.uid)
  .child("Accepted")
  .child(id).observeSingleEvent(of: .value, with: {(accepted) in 

}
...