In this example, the PositionPacket is just a struct. The following line then puts that struct into an NSData which is just a "byte bucket" object.
NSData *packet = [NSData dataWithBytes: &msg length: sizeof(PositionPacket)];
So if you just wanted to send an int score, you could have a sendScore method that looked like this:
- (void) sendScore
{
NSError *error;
int myScore = self.score;
NSData *packet = [NSData dataWithBytes:&myScore length:sizeof(myScore)];
[match sendDataToAllPlayers: packet withDataMode: GKMatchSendDataUnreliable error: &error];
if (error != nil)
{
// handle the error
}
}
Typically, you'll want a struct so that there's some additional information that lets the receivers know what kind of data it is. In the example, that would have been the purpose of this line:
msg.messageKind = PositionMessage;
In general, you can send anything you want encapsulated in an NSData object, since it's just a byte bucket. You can send primitive types like ints, or structs as in the example, or even NSObjects (as long as they implement NSCoding). You should read up on NSKeyedArchiver, NSCoding, and NSData for more information on sending and receiving NSObjects in this way. Here is Apple's reference document on Archving.
As for receiving, YOU don't call the method, it gets called ON you by the Kit. It's what's called a "delegate method" (in Cocoa parlance) or a "callback method." You can think of it like a "phone call" that your app can receive asynchronously. By implementing a method with the signature:
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID;
...you are saying "I can receive this kind of phone call." So when the GameKit receives data on your behalf from another player, it will see that you want to receive callbacks of that kind and will then call that method -- then it's up to you to update your internal application state based on what is received.
To continue with this example, if you had sent the simple "nothing but an integer" message described above, you might implement that method like this:
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID
{
int* receivedScorePtr = (int*)[data bytes];
int receivedScore = *receivedScorePtr;
[self updateScore: received forPlayer: playerID];
}
That is, of course, assuming that you have a method called updateScore:forPlayer: that would update a table of scores.
You can find a more general discussion/explanation of how delegates and delegate methods work at this blog entry: http://mohrt.blogspot.com/2010/01/cocoa-and-delegates.html
ADDED: Using code the asker posted, I made a few modifications and produced a version that "works" for this bare bones use case. Working Version of Test App To Send One Integer Through GameCenter I make no claims about the quality of the code, or its suitability for, well, anything at all. I didn't write 99.9% of it - please don't take my posting of it here as an endorsement of anything that appears in it.
One lesson learned (that I didn't know, so I'm putting here in hopes that it helps others) is that you can't use the Matchmaking service with the simulator. This means that you need two development-provisioned iOS devices in order to test this scenario, and likely, for non-trivial programs, two development machines to debug both devices simultaneously. This problem cost me the most time while figuring this out.