【问题标题】:ignore the following properties in swift Codable?忽略 swift Codable 中的以下属性?
【发布时间】:2020-10-17 03:00:34
【问题描述】:

我有这个 Account 结构。当我发送“POST”端点并使用它们将成功解码返回给快速对象时,我想忽略以下属性环境和编码到 JSON 对象的 ID

更新我有这个错误属性类型“[Environment]”与它的包装类型“SkipEncode”的“wrappedValue”属性不匹配

struct Account: Codable {
    let accountID, displayName, managedByID, id: String
    let environments: [Environment]
    let contacts: [Contact]

    enum CodingKeys: String, CodingKey {
        case accountID
        case displayName
        case managedID
        case id
        case environments
        case contacts
    }
}

【问题讨论】:

  • 你说的忽略,是指编码时还是解码时?
  • 当我发送“POST”端点并使用它们将成功解码返回给 swift 对象时,在编码到 JSON 对象时忽略它们
  • 不相关,但这里实际上不需要CodingKeys
  • 我使用 CodingKeys 映射到 JSON 属性的名称不同
  • @NinjaDeveloper 与您的问题无关,但您的编码密钥与 struct managedID 中的属性不匹配!= managedByID

标签: json swift codable urlsession


【解决方案1】:

另一种方法,如果您不想手动实现encode(to:) 并放弃Codable 自动合成的好处,您可以创建一个属性包装器作为标记您想要跳过的属性的一种方式:

@propertyWrapper
struct SkipEncode<T> {
   var wrappedValue: T
}

extension SkipEncode: Decodable where T: Decodable {
   init(from decoder: Decoder) throws {
      let container = try decoder.singleValueContainer()
      self.wrappedValue = try container.decode(T.self)
   }
}

extension SkipEncode: Encodable {
   func encode(to encoder: Encoder) throws {
      // nothing to do here
   }
}

extension KeyedEncodingContainer {
   mutating func encode<T>(_ value: SkipEncode<T>, forKey key: K) throws {
      // overload, but do nothing
   }
}

那么你可以像这样使用@SkipEncode

struct Account: Codable {
    let accountID, displayName, managedByID: String
    let contacts: [Contact]
    
    @SkipEncode
    let id: String

    @SkipEncode 
    let environments: [Environment]
}

【讨论】:

  • self.wrappedValue = try decoder.singleValueContainer().decode(String.self)
  • 顺便说一句,这是错误的,你不能包装环境它不是一个字符串。你需要一个通用的属性包装器stackoverflow.com/a/64399046/2303865
  • 啊...拍摄..复制粘贴错误很好,@LeoDabus。
  • 不..你是对的,它有效..不确定之前发生了什么。我很生气不得不实施它:) 所以,很好摆脱
  • 是的,我的游乐场有问题,确实需要通用解码
【解决方案2】:

如果你想忽略,例如environments编码时,你可以定义自己的编码实现:

struct Account: Codable {
    let accountID, displayName, managedByID, id: String
    let environments: [Environment]
    let contacts: [Contact]

    enum CodingKeys: String, CodingKey {
        case accountID, displayName, managedByID, id, environments, contacts
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(accountID, forKey: .accountID)
        try container.encode(displayName, forKey: .displayName)
        // ... just don't include the environments here
    }
}

【讨论】:

  • 这是错误的编码键与属性不匹配
  • @LeoDabus 你能详细说明一下吗?
  • 没有 managedID 属性。它应该由 ID 管理
  • @LeoDabus 哦,很好,我错过了,现在我将编辑我的答案。我直接从问题中复制了代码。
  • 我只想删除编码键。你不需要它们。
【解决方案3】:

按照 NewDev 建议的方法进行跟进。如果你想实现一个属性包装器,你需要实现一个通用的,以便能够跳过任何属性,而不仅仅是字符串:

@propertyWrapper
struct SkipEncode<T: Decodable> {
   var wrappedValue: T
}

extension SkipEncode: Codable {
    init(from decoder: Decoder) throws {
       wrappedValue = try decoder.singleValueContainer().decode(T.self)
    }
    func encode(to encoder: Encoder) throws { }
}

extension KeyedEncodingContainer {
    mutating func encode<T>(_ value: SkipEncode<T>, forKey key: K) throws { }
}

游乐场测试:

结构环境:可编码 { } struct Contact: Codable { }

struct Account: Codable {
    let accountID, displayName, managedByID: String

    @SkipEncode
    var id: String

    @SkipEncode
    var environments: [Environment]
    
    let contacts: [Contact]
}

let account = Account.init(accountID: "account", displayName: "name", managedByID: "manager", id: "id", environments: [], contacts: [])
let dt = try JSONEncoder().encode(account)
print(String.init(data: dt, encoding: .utf8)!) // {"accountID":"account","contacts":[],"managedByID":"manager","displayName":"name"}

【讨论】:

    猜你喜欢
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-23
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多