Game Center - 使用 Swift 发送和接收数据

Game Center - sending and receiving data with Swift

我正在尝试将以下结构从一个播放器发送到另一个播放器:

struct GamePacket {
    var action: String
    var pointArray: [CGPoint]
}

我很难找出将 GamePacket 转换为 Data 并再次转换回来的正确方法。

这是我目前用于发送数据包的代码:

func send(packet: GamePacket) {
    //convert GamePacket to Data here
    let data = Data.init()

    var remotePlayerArray = [GKPlayer]()

    if let currentPlayer = self.currentPlayer, let match = self.match, let playerArray = self.match?.players {
        for player in playerArray {
            if player != currentPlayer {
                remotePlayerArray.append(player)
            }
        }

        do {
            try match.send(data, to: remotePlayerArray, dataMode: GKMatchSendDataMode.reliable)
        }
        catch {
            print("connectionError")
        }
    }
}

以及接收的代码:

func match(_ match: GKMatch, didReceive data: Data, fromRemotePlayer player: GKPlayer) {
    //convert Data to GamePacket here
}

从一些用 ObjectiveC 编写的示例中,我设法使用类似于以下内容的方法将 GamePacket 转换为 Data

let data = NSData(bytes: &packet, length: MemoryLayout<GamePacket>.size) as Data

但是,我不知道如何在接收端将 Data 转换回 GamePacket,我也不确定这是正确的方法。

非常感谢任何帮助。谢谢。

一个快速而肮脏的解决方案是这样的:

func encodeGamePacket(packet: GamePacket) -> NSData {
    return NSData(bytes: &gamePacket, length: MemoryLayout<GamePacket>.size)
}

func decodeGamePacket(data: NSData) -> GamePacket? {
    var tempBuffer:GamePacket? = nil
    data.getBytes(&tempBuffer, length: MemoryLayout<GamePacket>.size)
    return tempBuffer
}

我自己还没有在 swift 下弄乱直接地址,所以我不完全确定这是否是最好的方法。请注意,我使用了可选的 return 类型,您可以在代码中进行不同的设计(可能添加一些检查,打开变量并 return 它,或者在检查失败时抛出异常)。

或者,您可以设计一种方法,将 GamePacket 写入 String(例如,为了提高可读性),然后您可以将其转换为 NSData(字符串具有data 方法),或者您将 GamePacket 变成符合 NSCoding 的 class,它提供了将自身转换为 NSData 的方法。

使用Codable

struct GamePacket: Codable {
  var action: String
  var pointArray: [CGPoint]
}

然后您可以轻松转换为Data

func save<T: Encodable>(_ item: T, to url: URL) throws -> Data {
  let encoder = JSONEncoder()
  return try encoder.encode(item)
}
func load<T: Decodable>(from data:Data) throws -> T {
  let decoder = JSONDecoder()
  let item = try decoder.decode(T.self, from: data)
  return item
}