Json Swift 4可解码变量可以是布尔类型,也可以是自定义类型

Json Swift 4可解码变量可以是布尔类型,也可以是自定义类型,json,swift4,decodable,Json,Swift4,Decodable,我已经为此挣扎了一段时间。我有一个从API调用获得的JSON,但它有一个键,可以是false,也可以是true,如果是true,则返回一个值 像这样: { "id": 550, "favorite": true, "rated": { "value": 8 }, "watchlist": false } struct AccountState: Decodable { var id: Int? var favorite: Bool? var

我已经为此挣扎了一段时间。我有一个从API调用获得的JSON,但它有一个键,可以是false,也可以是true,如果是true,则返回一个值

像这样:

{
  "id": 550,
  "favorite": true,
  "rated": {
    "value": 8
  },
  "watchlist": false
}
struct AccountState: Decodable {
    var id: Int?
    var favorite: Bool?
    var rated: CustomValue
    var watchlist: Bool?
}

struct RatingValue: Decodable {
    var value: Double?
}

enum CustomValue: Decodable {
    case bool(Bool)
    case rating(RatingValue)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()

        if let bool = try? container.decode(Bool.self) {
            self = .bool(bool)
        } else if let rating = try? container.decode(RatingValue.self) {
            self = .rating(rating)
        } else {
            let context = DecodingError.Context(codingPath: container.codingPath, debugDescription: "Unknown type")
        throw DecodingError.dataCorrupted(context)
        }
    }
}
或者这个:

{
  "id": 550,
  "favorite": true,
  "rated": false,
  "watchlist": false
}
我试着这样解码:

{
  "id": 550,
  "favorite": true,
  "rated": {
    "value": 8
  },
  "watchlist": false
}
struct AccountState: Decodable {
    var id: Int?
    var favorite: Bool?
    var rated: CustomValue
    var watchlist: Bool?
}

struct RatingValue: Decodable {
    var value: Double?
}

enum CustomValue: Decodable {
    case bool(Bool)
    case rating(RatingValue)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()

        if let bool = try? container.decode(Bool.self) {
            self = .bool(bool)
        } else if let rating = try? container.decode(RatingValue.self) {
            self = .rating(rating)
        } else {
            let context = DecodingError.Context(codingPath: container.codingPath, debugDescription: "Unknown type")
        throw DecodingError.dataCorrupted(context)
        }
    }
}
在ViewController中:

func dowloadAndDecodeData() {
 let url...
 ...

 let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            guard let accountState = try? decoder.decode(AccountState.self, from: data) else {
                print("error")
                return
            }
 print(accountState)
}
在控制台中,我可以看到JSON内容被正确解析(如果存在,则返回false或value)


问题是:如何从代码中访问此值?由于“rated”属于“CustomValue”类型,我不能像通常使用的那样只执行
accountState.rated.value

要访问类似
CustomValue
enum
带有关联值的案例),需要使用开关案例或if案例

    switch accountState.rated {
    case .rating(let ratingValue):
        print(ratingValue.value)
    case .bool(let boolValue):
        print(boolValue);
    }

或者,您可以为
CustomValue
定义一个简单的扩展:

extension CustomValue {
    var value: Double? {
        switch self {
        case .rating(let ratingValue):
            return ratingValue.value
        case .bool: //### in case .bool, return nil
            return nil
        }
    }
}
您可以通过以下方式简单访问:

    if let value = accountState.rated.value {
        print(value)
    }

我也面临着同样的问题,我把财产称为“任何”。所以我可以将其转换为所需的数据类型

在这里检查我的答案

我没有添加布尔类型,但它将100%解决您的问题,让我知道如果您需要进一步的帮助

在CustomValue类中添加以下属性之前,请阅读我的答案

 var any:Any{
        get{
            switch self {
            case .bool(let value):
                return value
            }
        }
    }