【问题标题】:swift 4 Codable - how to decode if there is string or dictionary?swift 4 Codable - 如果有字符串或字典,如何解码?
【发布时间】:2019-01-07 16:13:06
【问题描述】:

我有这样的结构:

struct OrderLine: Codable{
    let absUrl: String?
    let restApiUrl : String?
    let description : String?
    let quantity : Int?
    let subscription: Subs?
    let total: Double?
 }

struct Subs: Codable{
    let quantity: Int?
    let name: String?
}

还有一些OrderLine 在服务器响应中

"subscription": {
   "quantity": 6,
   "name": "3 Months"
},

但有时它有String 类型:

"subscription": "",

没有subscription 一切正常,但我有一个错误

CodingKeys(stringValue: "subscription", intValue: nil)], 
   debugDescription: "Expected to decode Dictionary<String, Any> 
   but found a string/data instead.", underlyingError: nil)

所以我的问题是 - 我如何解码或解码 String? 与价值 ""Subs? 没有任何错误? p.s.如果我只像String? 那样解码它,那么就会出现错误debugDescription: "Expected to decode String but found a dictionary instead.", underlyingError: nil)

【问题讨论】:

  • 你控制这个 API 吗?如果你这样做了,修复它,使subscription 在未定义时具有值null ,而不是""。如果您无法控制此 API,那么您必须实现自己的 init(from: Decoder)(而不是依赖编译器合成的默认值),在其中进行类型检查并处理这种情况
  • 您的 API 是否曾经为 subscription 返回有效(非空)String 值?还是在没有subscription 值的情况下只返回一个空字符串?
  • if let subscription = ((try? JSONSerialization.jsonObject(with: responseData)) as? [String: Any] ?? [:])["subscription"] as? String { if !subscription.isEmpty { print("decode") } else { print("subscription is empty") } }
  • 这样就不用实现自定义解码器了

标签: swift codable


【解决方案1】:

您只需要自己实现init(from:) 并尝试将subscription 键的值解码为代表SubsDictionaryString

struct OrderLine: Codable {
    let absUrl: String?
    let restApiUrl : String?
    let description : String?
    let quantity : Int?
    let subscription: Subs?
    let total: Double?

    private enum CodingKeys: String, CodingKey {
        case absUrl, restApiUrl, description, quantity, subscription, total
    }

    init(from decoder:Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.absUrl = try container.decodeIfPresent(String.self, forKey: .absUrl)
        self.restApiUrl = try container.decodeIfPresent(String.self, forKey: .restApiUrl)
        self.description = try container.decodeIfPresent(String.self, forKey: .description)
        self.quantity = try container.decodeIfPresent(Int.self, forKey: .quantity)
        self.total = try container.decodeIfPresent(Double.self, forKey: .total)
        if (try? container.decodeIfPresent(String.self, forKey: .subscription)) == nil {
            self.subscription = try container.decodeIfPresent(Subs.self, forKey: .subscription)
        } else {
            self.subscription = nil
        }
    }
}

【讨论】:

    猜你喜欢
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 2018-06-11
    • 2017-12-25
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多