json 如何从 Swift 4 的 Codable 中排除属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44655562/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:57:09  来源:igfitidea点击:

How to exclude properties from Swift 4's Codable

jsonswiftcodable

提问by RamwiseMatt

Swift 4's new Encodable/Decodableprotocols make JSON (de)serialization quite pleasant. However, I have not yet found a way to have fine-grained control over which properties should be encoded and which should get decoded.

Swift 4 的新Encodable/Decodable协议使 JSON(反)序列化变得非常愉快。但是,我还没有找到一种方法来细粒度控制哪些属性应该被编码,哪些应该被解码。

I have noticed that excluding the property from the accompanying CodingKeysenum excludes the property from the process altogether, but is there a way to have more fine-grained control?

我注意到从附带的CodingKeys枚举中排除属性会完全从过程中排除该属性,但是有没有办法进行更细粒度的控制?

回答by Code Different

The list of keys to encode/decode is controlled by a type called CodingKeys(note the sat the end). The compiler can synthesize this for you but can always override that.

要编码/解码的密钥列表由称为CodingKeys(注意s末尾的)的类型控制。编译器可以为您合成它,但始终可以覆盖它。

Let's say you want to exclude the property nicknamefrom both encoding anddecoding:

假设您想nickname从编码解码中排除该属性:

struct Person: Codable {
    var firstName: String
    var lastName: String
    var nickname: String?

    private enum CodingKeys: String, CodingKey {
        case firstName, lastName
    }
}


If you want it to be asymmetric (i.e. encode but not decode or vice versa), you have to provide your own implementations of encode(with encoder: )and init(from decoder: ):

如果您希望它是非对称的(即编码但不解码,反之亦然),您必须提供自己的encode(with encoder: )and实现init(from decoder: )

struct Person: Codable {
    var firstName: String
    var lastName: String

    // Since fullName is a computed property, it's excluded by default
    var fullName: String {
        return firstName + " " + lastName
    }

    private enum CodingKeys: String, CodingKey {
        case firstName
        case lastName
        case fullName
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        firstName = try container.decode(String.self, forKey: .firstName)
        lastName = try container.decode(String.self, forKey: .lastName)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(firstName, forKey: .firstName)
        try container.encode(lastName, forKey: .lastName)
        try container.encode(fullName, forKey: .fullName)
    }
}

回答by Hrishikesh Devhare

If we need to exclude decoding of a couple of properties from a large set of properties in the structure, declare them as optional properties. Code to unwrapping optionals is less than writing a lot of keys under CodingKey enum.

如果我们需要从结构中的大量属性中排除几个属性的解码,请将它们声明为可选属性。解包可选项的代码比在 CodingKey 枚举下编写大量键要少。

I would recommend using extensions to add computed instance properties and computed type properties. It separates codable comforming properties from other logic hence provides better readability.

我建议使用扩展来添加计算实例属性和计算类型属性。它将可编码的符合属性与其他逻辑分开,因此提供了更好的可读性。

回答by infiniteLoop

I have used protocol and its extension along with AssociatedObject to set and get image (or any property which needs to be excluded from Codable) property.

我已经使用协议及其扩展以及 AssociatedObject 来设置和获取图像(或任何需要从 Codable 中排除的属性)属性。

With this we dont have to implement our own Encoder and Decoder

有了这个,我们不必实现我们自己的编码器和解码器

Here is the code, keeping relevant code for simplicity:

这是代码,为简单起见,保留相关代码:

protocol SCAttachmentModelProtocol{
    var image:UIImage? {get set}
    var anotherProperty:Int {get set}
}
extension SCAttachmentModelProtocol where Self: SCAttachmentUploadRequestModel{
    var image:UIImage? {
        set{
            //Use associated object property to set it
        }
        get{
            //Use associated object property to get it
        }
    }
}
class SCAttachmentUploadRequestModel : SCAttachmentModelProtocol, Codable{
    var anotherProperty:Int
}

Now, whenever we want to access the Image property we can use on the object confirming to protocol (SCAttachmentModelProtocol)

现在,每当我们想要访问 Image 属性时,我们都可以在确认协议的对象上使用(SCattachmentModelProtocol)

回答by Beta-Logics

You can use computed properties:

您可以使用计算属性:

struct Person: Codable {
  var firstName: String
  var lastName: String
  var nickname: String?

  var nick: String {
    get {
      nickname ?? ""
    }
  }

  private enum CodingKeys: String, CodingKey {
    case firstName, lastName
  }
}

回答by Aleksei Kiselev

Another way to exclude some properties from encoder, separate coding container can be used

另一种从编码器中排除某些属性的方法,可以使用单独的编码容器

struct Person: Codable {
    let firstName: String
    let lastName: String
    let excludedFromEncoder: String

    private enum CodingKeys: String, CodingKey {
        case firstName
        case lastName
    }
    private enum AdditionalCodingKeys: String, CodingKey {
        case excludedFromEncoder
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let anotherContainer = try decoder.container(keyedBy: AdditionalCodingKeys.self)
        firstName = try container.decode(String.self, forKey: .firstName)
        lastName = try container.decode(String.self, forKey: .lastName)

        excludedFromEncoder = try anotherContainer(String.self, forKey: . excludedFromEncoder)
    }

    // it is not necessary to implement custom encoding
    // func encode(to encoder: Encoder) throws

    // let person = Person(firstName: "fname", lastName: "lname", excludedFromEncoder: "only for decoding")
    // let jsonData = try JSONEncoder().encode(person)
    // let jsonString = String(data: jsonData, encoding: .utf8)
    // jsonString --> {"firstName": "fname", "lastName": "lname"}

}

same approach can be used for decoder

相同的方法可用于解码器

回答by Patru

While this canbe done it ultimately ends up being very unSwiftyand even unJSONy. I think I see where you are coming from, the concept of #ids is prevalent in HTML, but it is rarely transported over to the world of JSONwhich I consider a good thing(TM).

虽然这可以做到,但最终会变得非常unSwifty甚至unJSONy。我想我知道你来自哪里,#ids的概念在 HTML 中很普遍,但它很少被转移到JSON我认为是一件好事(TM)的世界。

Some Codablestructs will be able to parse your JSONfile just fine if you restructure it using recursive hashes, i.e. if your recipejust contains an array of ingredientswhich in turn contains (one or several) ingredient_info. That way the parser will help you to stitch your network together in the first place and you only have to provide some backlinks through a simple traversal the structure if you really need them. Since this requires a thorough rework of your JSONandyour data structure I only sketch out the idea for you to think about it. If you deem it acceptable please tell me in the comments then I could elaborate it further, but depending on the circumstances you may not be at the liberty to change either one of them.

如果您使用递归散列对其进行重组,则某些Codable结构将能够JSON很好地解析您的文件,即,如果您recipe只包含一个数组,ingredients而该数组又包含 (一个或多个) ingredient_info。这样,解析器首先会帮助您将网络拼接在一起,如果您真的需要它们,您只需通过简单的结构遍历提供一些反向链接。由于这需要对您JSON您的数据结构进行彻底的返工,因此我只是勾勒出您可以考虑的想法。如果您认为可以接受,请在评论中告诉我,然后我可以进一步详细说明,但根据情况,您可能无权更改其中任何一个。