简体   繁体   English

JSONDecoder 解码不同类型的相同

[英]JSONDecoder decode same fromat different type

I'm using JSONDecoder to parse my JSON response:我正在使用 JSONDecoder 解析我的 JSON 响应:

{"status":"1","errorCode":"0","msg":"","info":1}

or或者

{"status":"1","errorCode":"0","msg":"","info":"a"}

or或者

{"status":"1","errorCode":"0","msg":"","info":{"name":"a"}}

or或者

{"status":"1","errorCode":"0","msg":"","info":{"text":"b"}}

or或者

{"status":"1","errorCode":"0","msg":"","info":[{"name":"a"}]}

Here is my basejson这是我的basejson

import Foundation

class BaseJson: Decodable {
    var id = UUID()
    var status: String
    var errorCode: String
    var msg: String

    private enum CodingKeys: String, CodingKey {
        case status = "status", errorCode = "errorCode", msg = "msg", info = "info"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        status = try container.decodeIfPresent(String.self, forKey: .status) ?? "0"
        errorCode = try container.decodeIfPresent(String.self, forKey: .errorCode) ?? "0"
        msg = try container.decodeIfPresent(String.self, forKey: .msg) ?? "1"
    }
}

So what should I do to make this basic class parse all the results那么我应该怎么做才能使这个基本的 class 解析所有结果

You can use a Enum with associated value to handle that.您可以使用具有关联值的 Enum 来处理它。

But as said by vadian, if you can, it's better that the API responds always the same kind of data according to the same parameters.但是正如vadian所说,如果可以,最好API根据相同的参数始终响应相同类型的数据。

You can add this:你可以添加这个:

enum Info: Decodable {

    enum DecodingError: Error {
        case unknownValueType
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let asInt = try? container.decode(Int.self) {
            self = .intValue(asInt)
        } else if let asString = try? container.decode(String.self) {
            self = .stringValue(asString)
        } else if let asDict = try? container.decode([String: String].self) {
            self = .dictValue(asDict)
        } else if let asArrayofDicts = try? container.decode([[String: String]].self) {
            self = .arrayOfDictValue(asArrayofDicts)
        } else {
            throw Info.DecodingError.unknownValueType
        }
    }

    case intValue(Int)
    case stringValue(String)
    case dictValue([String: String])
    case arrayOfDictValue([[String: String]])
}

I used [String: String] and [[String: String]] , but if that's limited you can also put your own custom struct:我使用了[String: String][[String: String]] ,但如果有限制,您也可以放置自己的自定义结构:

struct InfoText: Decodable { let text: String } struct InfoText:可解码 { 让文本:字符串 }

struct InfoName: Decodable { let name: String }结构信息名称:可解码 { 让名称:字符串 }

and do:并做:

case infoText(InfoText)案例信息文本(信息文本)

if let asInfoText = try?如果让 asInfoText = 试试? container.decode(InfoText.self) {... } container.decode(InfoText.self) {... }

etc.等等

Full code and text (copy pastable in Plyagrounds):完整的代码和文本(在 Plyagrounds 中复制粘贴):

class BaseJson: Decodable {

    enum Info: Decodable {

        enum DecodingError: Error {
            case unknownValueType
        }

        init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            if let asInt = try? container.decode(Int.self) {
                self = .intValue(asInt)
            } else if let asString = try? container.decode(String.self) {
                self = .stringValue(asString)
            } else if let asDict = try? container.decode([String: String].self) {
                self = .dictValue(asDict)
            } else if let asArrayofDicts = try? container.decode([[String: String]].self) {
                self = .arrayOfDictValue(asArrayofDicts)
            } else {
                throw Info.DecodingError.unknownValueType
            }
        }

        case intValue(Int)
        case stringValue(String)
        case dictValue([String: String])
        case arrayOfDictValue([[String: String]])
    }

    var id = UUID()
    var status: String
    var errorCode: String
    var msg: String
    var info: Info

    private enum CodingKeys: String, CodingKey {
        case status = "status", errorCode = "errorCode", msg = "msg", info = "info"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        status = try container.decode(String.self, forKey: .status)
        errorCode = try container.decode(String.self, forKey: .errorCode)
        msg = try container.decode(String.self, forKey: .msg)
        info = try container.decode(Info.self, forKey: .info)
    }

    static func test() {
        let jsonStr = """
[
{"status":"1","errorCode":"0","msg":"","info":1},
{"status":"1","errorCode":"0","msg":"","info":"a"},
{"status":"1","errorCode":"0","msg":"","info":{"name":"a"}},
{"status":"1","errorCode":"0","msg":"","info":{"text":"b"}},
{"status":"1","errorCode":"0","msg":"","info":[{"name":"a"}]}
]
"""

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

        do {
            let bases = try JSONDecoder().decode([BaseJson].self, from: jsonData)
            print(bases)

            for aBase in bases {
                var infoStr = ""
                switch aBase.info {
                case .arrayOfDictValue(let array):
                    infoStr = "\(array)"
                case .dictValue(let dictt):
                    infoStr = "\(dictt)"
                case .intValue(let intV):
                    infoStr = "\(intV)"
                case .stringValue(let str):
                    infoStr = str
                }
                print("Got: \(aBase.id), status: \(aBase.status), errorCode: \(aBase.errorCode), msg: \(aBase.msg), info: \(aBase.info) - badStringConversion for understanding: \(infoStr)")
            }
        } catch {
            print("Error: \(error)")
        }
    }
}

BaseJson.test()

Output: Output:

$> [__lldb_expr_75.BaseJson, __lldb_expr_75.BaseJson, __lldb_expr_75.BaseJson, __lldb_expr_75.BaseJson, __lldb_expr_75.BaseJson]
$> Got: C92A4315-413C-4DA3-9D0B-E6CE3B081AF3, status: 1, errorCode: 0, msg: , info: intValue(1) - badStringConversion for understanding: 1
$> Got: 1AB9FE74-E282-4AC9-97B1-814DD5C9F412, status: 1, errorCode: 0, msg: , info: stringValue("a") - badStringConversion for understanding: a
$> Got: F082FD0D-818D-4A6F-906A-3A80D911C2BA, status: 1, errorCode: 0, msg: , info: dictValue(["name": "a"]) - badStringConversion for understanding: ["name": "a"]
$> Got: 2424AFD2-8417-4FCB-B97A-D03AB30A9C45, status: 1, errorCode: 0, msg: , info: dictValue(["text": "b"]) - badStringConversion for understanding: ["text": "b"]
$> Got: 05DDB7CB-DD0E-41BB-B878-F1AEBF0D6F43, status: 1, errorCode: 0, msg: , info: arrayOfDictValue([["name": "a"]]) - badStringConversion for understanding: [["name": "a"]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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