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

Posted

技术标签:

【中文标题】Game Center - 使用 Swift 发送和接收数据【英文标题】:Game Center - sending and receiving data with Swift 【发布时间】:2016-11-18 09:24:11 【问题描述】:

我正在尝试将以下结构从一个玩家发送到另一个玩家:

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,我也不确定这是正确的方法。

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

【问题讨论】:

【参考方案1】:

使用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

【讨论】:

一样快,但不那么脏。 :) 我刚遇到同样的问题,很高兴找到您的解决方案@Tyler A.,谢谢!不幸的是,我还剩下两个问题:1. 我不知道如何处理 URL 参数,因为我试图将解码后的数据保存在像 var message = load(from: data) 这样的变量中 2. 当按照 1 中的描述进行操作时,我得到了错误Generic parameter 'T' could not be inferred你能帮忙吗?【参考方案2】:

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

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 下弄乱直接地址,所以我不完全确定这是否是最好的方法。请注意,我使用了可选的返回类型,您可以在代码中进行不同的设计(可能添加一些检查、解包变量并返回它,或者在检查失败时抛出异常)。

或者,您可以设计一个方法,将您的GamePacket 写入String(例如,为了便于阅读),然后您可以将其转换为NSData(字符串有一个data 方法)或者您转将GamePacket 转换为符合NSCoding 的类,该类也提供将自身转换为NSData 的方法。

【讨论】:

以上是关于Game Center - 使用 Swift 发送和接收数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 iOS Game Center Challenge 发送对象?

向/从 Game Center 发送/检索分数对

将分数发布到 Game Center 排行榜

Game Center 排行榜更高的分数在发送时不会更新

Game Center 的持久数据?

Game Center 沙盒中缺少邀请