-->

How to list all available GKTurnBasedMatches for a

2020-03-25 11:13发布

问题:

I'm building a game using Game Center's turn based matches.

I want to display a list of all the available matches. I've tried using loadMatchesWithCompletionHandler(), but the array of games returns as nil, and the error also returns as nil. There are some ongoing matches.

This is what I have so far:

func authenticateLocalUser() {
    if !gameCenterAvailable { return }

    let player = GKLocalPlayer.localPlayer()
    if player.authenticated == false {
        player.authenticateHandler = {(viewController, error) -> Void in
            if viewController != nil && self.presentingViewController != nil
            {
                self.presentingViewController!.presentViewController(viewController!, animated: true, completion: {
                    GKLocalPlayer.localPlayer().registerListener(self)

                    GKTurnBasedMatch.loadMatchesWithCompletionHandler({games, error in
                        print(games)
                        if games != nil {
                            print(games!.count)
                        }else {
                            print(error)
                        }
                    })
                })
            } else {

                if player.authenticated == true {
                    GKLocalPlayer.localPlayer().registerListener(self)

                    GKTurnBasedMatch.loadMatchesWithCompletionHandler({games, error in
                        print(games)
                        if games != nil {
                            print(games!.count)
                        }else {
                            print(error)
                        }
                    })
                }
            }
        }
    } else {
        print("already authenticated")
    }
}

I even get nil when creating a new match (it will print the match I just created, though):

func findMatchWith(minPlayers: Int, maxPlayers: Int) {
    if !gameCenterAvailable { return }

    let request = GKMatchRequest()
    request.minPlayers = minPlayers
    request.maxPlayers = maxPlayers
    request.defaultNumberOfPlayers = 2

    GKLocalPlayer.localPlayer().loadFriendPlayersWithCompletionHandler({players, error in
        if error != nil {return}
        request.recipients?.append(players![0])

        GKTurnBasedMatch.findMatchForRequest(request, withCompletionHandler: { match, error in
            if error != nil {
                print(error?.localizedDescription)
                return
            }
            print(match)

            GKTurnBasedMatch.loadMatchesWithCompletionHandler({games, error in
                print(games)
                if games != nil {
                    print(games!.count)
                }else {
                    print(error?.localizedDescription)
                } 
            })
        })
    })
}

回答1:

It wasn't the code. It was how the game was set up in iTunes Connect. I needed to do this:

  1. Go to My App > App Store > Prepare for submission and toggle the switch for Game Center
  2. Add a leaderboard I had previously created under "Features"

Later, I will try to delete the leaderboard, and see if it still works. The actual app won't have a leaderboard.

My confusion was because I wasn't getting the "unrecognized game" error, and I was able to create matches, play turns, list player's friends, but not list matches.



回答2:

It's a little hard to tell from the snippet you've shown. Things to double check:

  1. Where are you creating matches? You probably already know this, but just in case: loadMatchesWithCompletionHandler shows the matches that you've created, been invited to, or joined. It does not show all matches out there waiting for players.
  2. The completion handler for presenting the login view controller will never successfully load any matches. That completion handler will fire as soon as the login view controller is successfully displayed. It does not wait until you've actually submitted login credentials. So that attempt to load matches will occur before you're authenticated and will always return null.
  3. Your completion handler will get called in two circumstances. It occurs once when you set the completion handler, as you would expect. It will be called again after the login view controller (if displayed) finishes executing. On the second instance, you could get errors if the user canceled or failed login. Or, you will appear to be an authenticated, logged in user with no VC.
  4. You've got a few assumptions in your authentication chain that won't always work out:

You assume if .authenticated is YES then you are logged in. Unfortunately, that's not always true. GC will report YES in conditions where it can't talk to GC servers but is using cached data from a prior session. (Usually, though, you'll actually get an error about not being authenticated when you attempt to load matches while in this state)

You assume if the VC is nil, then you are authenticated. That's not always true, either. If an error is set, the VC will also be nil. Always check the value of the error first thing in the authentication handler. (I don't think this contributes to your problem now, though, because again: you should get an error if you try to load matches when you're actually not authenticated)

If you're interested, you can see an example of my authentication handler, which catches a variety of edge cases and failures, at https://stackoverflow.com/a/37216566/1641444