1

On iOS 10 I am trying to create a match using the GKTurnBasedMatchmakerViewController. I can bring up the view so the user can choose matchmaking or an invite. I can't figure out how to reliably determine which match got created in response to that. The problem is that, in iOS 10, the didFindMatch method of the GKTurnBasedMatchmakerViewControllerDelegate has been deprecated. That method used to be called with the match. The old days were easy!

The deprecation message says "use GKTurnBasedEventListener player:receivedTurnEventForMatch:didBecomeActive". The docs and stack overflow threads are filled with reasons why that method gets called. See this thread for a good list: Gamecenter ios 9 GameCenter GKLocalPlayerListener methods not called. If you imagine a user that already has several games going, you can see that this method will be called for a lot of different reasons and it could happen at any time, as far as I know. My question is: how to determine which of these calls is the "I just created a match for you, here it is!" call.

Some examples I think won't work:

  • Simply assuming the first call to receivedTurnEventForMatch that happens after you bring up the GKTurnBasedMatchmakerViewController seems wrong since receivedTurnEventForMatch could be notifying the user that it is their turn in another game. Unless the system guarantees that, while the view is up, they will only call this method with the match that corresponds to the view. That seems like a pretty big hack, so I'm assuming they don't do it.
  • A call to receivedTurnEventForMatch with the other player in "Matching" state and didBecomeActive=true seems to be a solution for the first player in a match, but not the second (since both players are done matching).
  • Looking at the MatchID and seeing if we've "seen it before", and if not, assuming it is the match that just got created seems unreliable since the user might have uninstalled the app and then reinstalled and we've forgotten all about which matches we've "seen before".

I'm stuck, any help is appreciated.

Community
  • 1
  • 1
Eric Zinda
  • 787
  • 7
  • 15

1 Answers1

0

Double check your status when the event handler fires. I believe you should still be in invited state until you accept the match.

edit: Actually, I believe there will be two conditions that indicate a new match when the event handler fires:

  1. You are in the invited state (you joined)

  2. Everyone else is in the invited or automatch state (you started the match)

edit 2: Checking my old code, it turns out that I looked at the matchData object. Since I knew that player 2 doesn't receive the invite until player1 ended the turn (and so forth), and since I knew that player1 had to save match data in order to end the turn, if matchData.length was greater than zero, I assumed I was joining a game in progress. I didn't rely on the participant status. But that doesn't solve your problem.

The other thing I did was create my own header struct which I inserted at the start of the NSData. In that header, player1 would set status flags for each other player, that would be obvious when those players joined. I totally ignored the participant status in the match object.

Regarding your third bullet, instead of saving the list locally, you could save it remotely using cloudKit. The cloudkit data will persist across installs/uninstalls unless you specifically delete it.

The gist with cloudkit is:

  • when you enable it in your app, your app gets a "container" with a public database that all users can share plus a private database unique to each app user.
  • You can create a record in the private database with a "Bytes" field
  • You can save a NSMutableArray directly into the aforementioned Bytes field
  • You can read back a NSMutableArray directly from the Bytes field
Thunk
  • 4,099
  • 7
  • 28
  • 47
  • From my testing it doesn't work that way: If I start an automatic or invite game: I am in the GKTurnBasedParticipantStatusActive status, and the matching player is in the GKTurnBasedParticipantStatusMatching status. As I mention above: Detecting when receivedTurnEventForMatch is giving you the new game for the first player in a match seems straightforward: Look for the "matching" state. It is the second player that is the challenge since both have the state "Active" (which is also the case for lots of other times this event will get called). – Eric Zinda Dec 12 '16 at 22:37
  • @Eric, I reached my frustration limit with `GK*` and ripped all of that code out a few months ago. So, I had to go look through some old branches to see what I used to do. I've updated the answer, accordingly. – Thunk Dec 13 '16 at 04:34
  • totally understand the frustration, I'm about there too. I'll mark this answer as correct since it formed the basis of my solution (described next) – Eric Zinda Dec 14 '16 at 00:17
  • I ended up going with this logic: If receivedTurnEventForMatch gets called and: The MatchmakerViewController is up and the match has the other player in "matching" state, then this is the new matchmaking game. Otherwise if we don't have the match stored and (the matchdata is empty or in the "initial" state as defined by my game) and MatchmakerViewController is currently up, then this is a new matchmaking game where we are the second player to join. If all that is true except the viewController isn't up, then the user just accepted an invite by clicking on it. This handles all the cases. – Eric Zinda Dec 14 '16 at 00:17