Closure Ordering Problems

Hey guys, so I've been having a lot of trouble trying to get the async Firebase calls to work properly. I need to first fetch the Tournament data from Firestore before being able to fetch the specific Player data from Firestore. The closures are really not making sense to me and I'm trying to call fetchAllPlayers inside the fetchTournament closure but even then it gives me empty values. Can anyone help me understand the best way to wait for a closure to finish before calling another one?

Thanks!


class BracketViewModel {
  
    let firebase = FirebaseService.shared
    var tournamentID: String
    var tournamentData = Tournament()
    var totalPlayers = 0
    var playerList: [Player] = []
  
    init(_ tournamentID: String) {
        self.tournamentID = tournamentID
        self.firebase.fetchTournamentData(tournamentID) { tournament in
            self.tournamentData = tournament
            self.totalPlayers = tournament.numPlayers
            self.fetchAllPlayers { players in
                self.playerList = players
            }
        }
    }
  
    func fetchAllPlayers(completionHandler: @escaping (_ players: [Player]) -> Void) {
        var playerList = Array(repeating: Player(), count: totalPlayers)
        let queue = DispatchQueue(label: "Player Serial Queue")
        print(tournamentData.players) //Players exist here
        for (index, playerRef) in tournamentData.players.enumerated() { //But are empty here?
            queue.sync {
                print(playerRef)
                firebase.fetchPlayerData(playerRef) { playerData in
                    playerList[index] = playerData
                }
            }
        }
        queue.async {
            completionHandler(playerList)
        }
    }

wait for a closure to finish before calling another one cannot be the best way and using serial queue is not recommended,

but your code would succeed to retrieve all the players eventually.


What if you put `print(players)` before the line `self.playerList = players`?

(Please try code insertion feature shown with icon `< >`.)

Thanks for letting me know about the < >, first time positng here.

It's still empty there. Do you know what would be a better way then of getting this data? Because I need to access the player list from the tournament before I can try and fetch the player data...

Can you change your `fetchAllPlayers(completionHandler:)` as follows, and tell me what's printed in the debug console?

func fetchAllPlayers(completionHandler: @escaping (_ players: [Player]) -> Void) {
    var playerList = Array(repeating: Player(), count: totalPlayers)
    let group = DispatchGroup()
    print(tournamentData.players)
    for (index, playerRef) in tournamentData.players.enumerated() {
        print(index, playerRef)
        group.enter()
        firebase.fetchPlayerData(playerRef) { playerData in
            print(index, "player fetched")
            playerList[index] = playerData
            group.leave()
        }
    }
    group.notify(queue: .main) {
        print("notify triggered")
        completionHandler(playerList)
    }
}

So it prints everything that it should, It goes through all 8 players. What I realized though is that the Firebase DocumentReference is wrong for some reason and its returing nil for the Player.. Thanks for your help though!

Closure Ordering Problems
 
 
Q