How to handle Game Center updates occurring at the same time?

I use GameKItHelper as a base to process information sent from Game Center.


I just discovered the "match (didChange state: )" function is immediately being called twice, back to back at the same exact time, to indicate two other players in the match have connected. In addition, both separate function calls indicate "expectedPlayerCount = 0" so my match processing starts twice, thus resulting in bad things happening.


I experienced this in the past and added a "myMatchStarted" boolean flag to indicate when the match really started, so I could stop the match from starting a second time (see code below). This code was confirmed to be working for many various cases which would have originally failed, so I thought I resolved this issue.


However, I just experienced this issue one more time where my code updates (below) were still not good enough to block two simutaneous calls to the "match (didChange state: )" function if these functions occurred really really close to each other.


Please refer to the debug output (provided below the code snippet) to see how the function is being called twice extremely fast and how the "myMatchStarted" boolean flag did not even have a chance to be set for the first function call, thus could not stop the second call from being processed.


How should I process Game Center function calls which occur at the same time?



func match(_ match: GKMatch, player: GKPlayer, didChange state: GKPlayerConnectionState)
{
     print("(GAMEKIT) ENTER match() didChange state")

     switch (state)
     {
     case GKPlayerConnectionState.connected:

          print("(GAMEKIT)   PLAYER CONNECTED! = \(player.displayName)")

          if (myMatchStarted == false)
          {
               print("(GAMEKIT)   (match didChange) Match DID NOT start yet")
               if (match.expectedPlayerCount == 0)
               {
                    print("(GAMEKIT)   (match didChange) START THE MATCH!")
                    startMatch()
               }
          }

     etc..

}


func startMatch()
{
     print("(GAMEKIT) ENTER startMatch()")

     if (myMatchStarted == true)
     {
          print("(GAMEKIT) **    MATCH ALREADY STARTED, DO NOT START AGAIN !!    **")
          return
     }

     myMatchStarted = true

     loadOtherPlayerInfo()

     print("(GAMEKIT) EXIT startMatch()")
 }



LOG OUTPUT

(GAMEKIT) ENTER match() didChange state
(GAMEKIT) ENTER match() didChange state
(GAMEKIT) PLAYER CONNECTED! = Bob
(GAMEKIT) PLAYER CONNECTED! = Mary
(GAMEKIT) (match didChange) Match DID NOT start yet
(GAMEKIT) (match didChange) START THE MATCH!
(GAMEKIT) (match didChange) Match DID NOT start yet
(GAMEKIT) (match didChange) START THE MATCH!
(GAMEKIT) ENTER startMatch()
(GAMEKIT) ENTER startMatch()
(GAMEKIT) ENTER loadOtherPlayerInfo
(GAMEKIT) ENTER loadOtherPlayerInfo
(GAMEKIT) EXIT startMatch()
(GAMEKIT) EXIT match() didChange state
(GAMEKIT) EXIT startMatch()
(GAMEKIT) EXIT match() didChange state

Accepted Reply

So far, it seems placing the call to the startMatch( ) function inside a DispatchQueue.main.async will guarantee the each separate CONNECT message will be processed in a serial fashion.

Replies

So far, it seems placing the call to the startMatch( ) function inside a DispatchQueue.main.async will guarantee the each separate CONNECT message will be processed in a serial fashion.

> inside a DispatchQueue.main.async will guarantee the each separate CONNECT message will be processed in a serial fashion


I'm not certain, but what you might be observing is not an issue with the order of 'processing'. The code will all be executed immediately when called no matter what queue it is on. But when code tries to change the screen (e.g. a UIAlertView) it doesn't actually change the screen but just logs those changes. Those changes will only appear on the screen when the queue ends and the system can process any requested changes to the screen. Since the queue that is returned in didChangeState, the queue on which you are logging the change, is kept busy, those changes don't get made until the queue finally stops being busy. That can take a random amount of time - hence the logged changes get pushed onto the screen at various times.