提问者:小点点

如何在swift中对不同数据类型密钥进行解码


我在用Swift将json解码成可编码模型时遇到了一些问题。 从服务器获得的json响应如下所示

{
  "code": 200,
  "data": {
    "Australia": {
      "address": "1111",
      "port": "443",
      "proto": "udp",
      "country": "au"
    },
    "Australia udp": {
      "address": "2222",
      "port": "443",
      "proto": "udp",
      "country": "au"
    },
    "Vietnam TCP": {
      "address": "3333",
      "port": "443",
      "proto": "tcp",
      "country": "vn"
    },
    "status": "1"
  }
}

现在我找到了其他关于如何解码简单数据类型的帖子,但是我没有找到解码复杂数据类型的帖子! 到目前为止我所做的就是这个模型

struct ListServers: Codable {
    let code: Int
    let data: [String: ListServersData]
}

enum ListServersData: Codable {
    case string(String)
    case innerItem(ServerInfo)
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        if let x = try? container.decode(ServerInfo.self) {
            self = .innerItem(x)
            return
        }
        throw DecodingError.typeMismatch(ListServersData.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for MyValue"))
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let x):
            try container.encode(x)
        case .innerItem(let x):
            try container.encode(x)
        }
    }
}

struct ServerInfo: Codable {
    let address, port, proto, country: String
}

但这会抛出一个错误!!

我不确定如何解码,因为我有响应的附加状态


共1个答案

匿名用户

请尝试以下操作:

只需在某处设置一个json字符串

let json =
"""
{
  "code": 200,
  "data": {
    "Australia": {
      "address": "1111",
      "port": "443",
      "proto": "udp",
      "country": "au"
    },
    "Australia udp": {
      "address": "2222",
      "port": "443",
      "proto": "udp",
      "country": "au"
    },
    "Vietnam TCP": {
      "address": "3333",
      "port": "443",
      "proto": "tcp",
      "country": "vn"
    },
    "status": "1"
  }
}
"""

然后设置与上面相同的结构和枚举:

struct ListServers: Codable {
    let code: Int
    let data: [String: ListServersData]
}

enum ListServersData: Codable {
    case string(String)
    case innerItem(ServerInfo)
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        if let x = try? container.decode(ServerInfo.self) {
            self = .innerItem(x)
            return
        }
        throw DecodingError.typeMismatch(ListServersData.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for MyValue"))
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let x):
            try container.encode(x)
        case .innerItem(let x):
            try container.encode(x)
        }
    }
}

struct ServerInfo: Codable {
    let address, port, proto, country: String
}

然后像这样解码json:

let jsonData = json.data(using: .utf8)!

do {
    let decoder = JSONDecoder()
    let result = try decoder.decode(ListServers.self, from: jsonData)
    print("Code: \(result.code)")
    
    for (_, v) in result.data {
        switch v {
        case .string(let string):
            print("Status: \(string)")
            
        case .innerItem(let serverInfo):
            print("Address: \(serverInfo.address)")
            print("Port: \(serverInfo.port)")
            print("Proto: \(serverInfo.proto)")
            print("Country: \(serverInfo.country)")
        }
        
        print("=======================")
    }
}
catch {
    print(error)
}

这就是正确打印出来的内容:

Code: 200
Address: 3333
Port: 443
Proto: tcp
Country: vn
=======================
Address: 2222
Port: 443
Proto: udp
Country: au
=======================
Status: 1
=======================
Address: 1111
Port: 443
Proto: udp
Country: au
=======================