Swift:解码从 GameKit 发送的消息

Posted

技术标签:

【中文标题】Swift:解码从 GameKit 发送的消息【英文标题】:Swift: Decode message sent from GameKit 【发布时间】:2020-03-31 17:09:23 【问题描述】:

我正在尝试在 GameKit 中接收消息。接收消息的部分运行良好,但我不知道如何正确解码数据。

enum MessageType: Int, Codable 
    case BestHost, GameBegin, YourTurn, PlayCard, GameOver


struct Message: Codable 
    let messageType: MessageType
    

struct MessageBestHost: Codable 
    let message: Message
    let bestHostId: String
    let bestHostName: String


我使用上述基础设施来发送和接收我的消息。对于发送,我将消息编码如下,然后将其发送给所有玩家:

func encode<T: Encodable>(_ item: T) throws -> Data 
    let encoder = JSONEncoder()
    return try encoder.encode(item)


func sendBestHost(player: GKPlayer) 

    let message = MessageBestHost(message: Message(messageType: MessageType.BestHost), bestHostId: player.gamePlayerID, bestHostName: player.alias)
    do 
        try sendDataToAllPlayers(data: encode(message))
    
    catch 
        print("Error: \(error.localizedDescription)")
    


接收时我使用这种方法解码数据:

func decode<T: Decodable>(from data:Data) throws -> T 
    let decoder = JSONDecoder()
    let item = try decoder.decode(T.self, from: data)
  return item


let message: Message
do 
    message = try decode (from: data)
    print(message)
 catch 
    print (error)


if message.messageType == MessageType.BestHost 
    do 
    let messageBestHost: MessageBestHost = try decode(from: data)
    print("\(messageBestHost.bestHostName) hosts the game")
 catch 
    print(error)


现在的问题是。我首先需要将消息解码为类型:消息,以便过滤正确的子类型并为引用消息类型发挥作用。当尝试将数据转换为 message 类型的变量时,解码(显然)失败,因为发送的数据不包含顶层层级中的 messageType。

Error: No value associated with key CodingKeys(stringValue: \"messageType\", intValue: nil)

如果不能先过滤messageType,我将无法区分不同的消息并执行不同的方法。

我想解决方案可能位于我的数据基础架构中,但我想不出任何方法来完成这项工作。有人知道如何解决这个问题吗?

【问题讨论】:

会不会根据类型本身有不同类型的Message或MessageBestHost?如果是这样,那么也许这会有所帮助:***.com/questions/59270672/… 如果不是,那么我不明白为什么你不能先将其解码为 MessageBestHost,然后再对其进行过滤。 mesasageType提到的所有类型的消息。我只是以 MessageBestHost 为例。这就是为什么我不能一直将它解码为 MessageBestHost,因为 messageType 会改变并且不会总是包含相同的数据。我刚刚查看了提供的链接。在那里你使用协议。我无法将您的示例与我的示例联系起来,因为我不使用协议。您认为在这里使用协议是正确的方法吗?谢谢! 这取决于您需要如何使用 MessageBestHost。如果在数组中,那么它们应该符合相同的协议。 【参考方案1】:

我可能会尝试这样的事情:

import Foundation

enum MessageType: Int, Codable 
    case BestHost, GameBegin, YourTurn, PlayCard, GameOver


struct Message: Codable 
    let messageType: MessageType
    let data: Data


struct MessageBestHost: Codable 
    let bestHostId: String
    let bestHostName: String


do 
    // Serialize:

    let messageBestHost = MessageBestHost(bestHostId: "id", bestHostName: "name")
    let messageBestHostData = try JSONEncoder().encode(messageBestHost)
    let message = Message(messageType: .BestHost, data: messageBestHostData)
    let messageData = try JSONEncoder().encode(message)
    try sendDataToAllPlayers(data: encode(message))

    // Deserialize:
    let messageReceived = try JSONDecoder().decode(Message.self, from: messageData)
    if messageReceived.messageType == .BestHost 
        let messageBestHostReceived = try JSONDecoder().decode(MessageBestHost.self, from: messageReceived.data)
        print(messageBestHostReceived.bestHostId)
        print(messageBestHostReceived.bestHostName)
    

 catch 
    print("Error: \(error.localizedDescription)")



Swift 枚举 case 也应该以小写字母开头

【讨论】:

以上是关于Swift:解码从 GameKit 发送的消息的主要内容,如果未能解决你的问题,请参考以下文章

是发送还是接收错误?未发送完整消息或未正确解码消息

在 Swift 中解码引用的可打印消息

无法解码来自 Websocket 的消息

SWIFT4将JSON解码结果发送到类进行处理

在 Swift iOS 中解码的 PHP JSON 返回空值

如何从 Swift 4 中的解码器容器中获取未解码的属性?