5

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)
                } 
            })
        })
    })
}
coopersita
  • 5,011
  • 3
  • 27
  • 48

2 Answers2

2

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.

coopersita
  • 5,011
  • 3
  • 27
  • 48
  • Can you clarify this for me a little bit? Are you talking about available matches across the board, among all players with matches, everywhere? From the documentation it appeared to me that `loadMatchesWithCompletionHandler` only returned matches the player was already a member of, and there was no way to retrieve globally-available matches. – Le Mot Juiced Feb 16 '17 at 16:39
  • 1
    @LeMotJuiced It was matches the user is currently participating in. – coopersita Feb 16 '17 at 22:30
0

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

Community
  • 1
  • 1
Thunk
  • 4,099
  • 7
  • 28
  • 47
  • Thanks. I thought, as you suggested, that perhaps I was trying to get the matches before authentication finished, so I created a button and waited until the "Welcome back X" message went away to click it, but still nothing. I'll give that code a try. – coopersita May 14 '16 at 19:39
  • I changed my `authenticateHandler`, as you suggested, and still nothing. I even create a new match in the app (not GC), then click the button to load matches, and still get `nil`. I did try to load matches before authentication, just to test, and I do get an error for that. – coopersita May 14 '16 at 20:26
  • I initially deleted this comment based on your second comment; however, it might still be a good test: have you tried loading matches from within `didFindMatch`? If you get to `didFindMatch` then you have to be authenticated and you had to have successfully produced a match. I'd call `loadMatchesWithCompletionHandler` right inside `didFindMatch` and put a breakpoint inside the completion handler to check what you received. – Thunk May 14 '16 at 21:33
  • Still `nil`. I added the code I have for `didFindMatch` in my original question. – coopersita May 14 '16 at 21:39
  • Another suggestion: temporarily comment out `request.recipients?.append(players![0])` when you're creating the match and see what happens. That's the only thing I see different from what I do, which works (albeit in Obj-c rather than swift). – Thunk May 19 '16 at 16:07
  • I finally was able to make it work! I ended up adding a leaderboard, even though I don't need it, to force Game Center to recognize the app. It weird that Game Center sort of recognizes the app to the point that I can create games, play, but won't list available games. Thanks for the help. – coopersita May 19 '16 at 16:20
  • Ah! that damn "you must have a leaderboard" thing. I didn't think of that because it didn;t throw the "unrecognized game" error. I'm going to edit the answer at http://stackoverflow.com/questions/34055758/ios9-this-game-is-not-recognized-by-game-center/34056115#34056115 to indicate it fails silently sometimes too. – Thunk May 19 '16 at 16:23
  • I would get that error once in a while, but if I just waited a bit, it would go away. Very annoying. I'll check your edit to that answer. It's a great resource. – coopersita May 19 '16 at 16:26
  • Whoops, I meant to link to this answer: http://stackoverflow.com/a/34056115/1641444 (too late to edit the prior comment now) – Thunk May 19 '16 at 17:03