Creating GameCentre Network messages in Swift

Normal disclaimer – I’m not a professional, this is capturing what I’ve learnt as I go.

This comes from a work in progress iPad app (frustration). It will contain real time multiplayer matches handled via GameCentre. Out of the many challenges I found, one for was creating appropriate network messages to send and receive.

Below is the final snippet of code I’ve put together along with a few descriptions.

struct frustrationNetworkMessage {
	var messageType : FrustrationNetworkMessageType
	var card : Card
	var actingPlayer : String
	init(messageType : FrustrationNetworkMessageType, card : Card, actingPlayer : String) {
		self.messageType = messageType
		self.card = card
		self.actingPlayer = actingPlayer

First thing I found when creating the network message is structs are your friend. A class variable will store the address in memory of the actual data, not the data itself. Not realising this gave me a fair number of initial strange errors.

Second thing I found was using basic data types as much as possible. All of my enumerations are of type UInt8 (so has a fixed size – makes extracting too/from NSData easier).

	func archive()->NSData {
		var localMessageType = messageType.rawValue
		var localCard = card
		let returnValue = NSMutableData(bytes: &localMessageType, length: sizeofValue(self.messageType.rawValue))
		returnValue.appendData(NSData(bytes: &localCard, length: sizeofValue(self.card)))
		return returnValue

The next challenge covered encoding the message into NSData for sending via GameCentre. The three main lessons I took from making this work were:

  • Encode the message using the struct itself. This keeps the logic isolated & makes it easier for code reuse later.
  • Pack the values of the struct in a defined order. This makes extracting each value upon receipt easier.
  • Pack the built in types first – class variables second. The built in types have a defined length so you always know where to find these later. The class types can be of a variable size, so these should go last.
init(data : NSData) {
		let messageTypeLength = sizeofValue(FrustrationNetworkMessageType)
		let cardLength = sizeofValue(Card)
		let messageTypeRange = NSMakeRange(0, messageTypeLength)
		let cardLengthRange = NSMakeRange(messageTypeLength, messageTypeLength + cardLength)
		let actingPlayerRange = NSMakeRange(messageTypeLength + cardLength, data.length)
		self.messageType = .didDiscardCard
		self.card = Card.emptyCard()
		data.getBytes(&self.messageType, range: messageTypeRange)
		data.getBytes(&self.card, range: cardLengthRange)
		let actingPlayerData = data.subdataWithRange(actingPlayerRange)
		self.actingPlayer = NSString(data: actingPlayerData, encoding: NSUTF8StringEncoding) as! String

The last challenge covered extracting the message information out of the NSData object. While the code is a bit clunky, it does the job. Since the values were encoded in a specific order, this simply reads the specified bytes and moves them into the necessary values.

Again with the archive method, this was kept as part of the struct. This keeps the logic isolated and should make later re-use easier.