简体   繁体   中英

Swift: Decode message sent from GameKit

I'm trying to receive messages in GameKit. The part of receiving the messages works well, but I can not figure out how to decode the data properly.

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
}

I use the above infrastructure for sending and receiving my messages. For sending I encode the message as follows and then send it to all players:

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)")
    }
}

When receiving I use this method to decode the data:

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)
}

The problem now is. I first need to decode the message as type: Message in order to filter for the correct Subtype and do the magic for the referencing messageType. When trying to cast the data into a variable of type message, the decoding (obviously) fails because the sent data does not contain a messageType in the top hierarchical level.

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

Without being able to filter for the messageType first I won't be able to distinguish between different messages and execute different methods.

I guess the solution might lay within my data infrastructure but I cant think of any way to make this work. Does anybody have a clue how to solve this problem?

I might try something like this:

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)")
}


Also swift enum cases should start with lowercase letter

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM