【问题标题】:Swift 4 decodable var can be either Bool or custom typeSwift 4 可解码 var 可以是 Bool 或自定义类型
【发布时间】:2018-08-14 09:00:37
【问题描述】:

我已经为此苦苦挣扎了一段时间。我有一个从 API 调用中获得的 JSON,但它有一个键,如果它是真的,它可以是假的或者返回一个值。

像这样:

{
  "id": 550,
  "favorite": true,
  "rated": {
    "value": 8
  },
  "watchlist": false
}

或者这个:

{
  "id": 550,
  "favorite": true,
  "rated": false,
  "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

【问题讨论】:

    标签: json swift4 decodable


    【解决方案1】:

    要访问类似CustomValue(具有关联值的enum 案例)之类的内容,您需要使用switch-case 或if-case。

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

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,我创建了一个名为 Any 的属性。所以我可以将它转换为所需的数据类型。

      在这里查看我的答案。 How to use Any in Codable Type

      我没有添加 bool 类型,但它会 100 % 解决您的问题,如果您需要进一步帮助,请告诉我

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

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

      【讨论】:

        猜你喜欢
        • 2017-07-20
        • 2021-01-11
        • 2018-10-05
        • 2019-03-21
        • 1970-01-01
        • 1970-01-01
        • 2019-01-11
        • 2017-11-07
        • 2014-11-22
        相关资源
        最近更新 更多