美文网首页
Codable in Swift 4.0

Codable in Swift 4.0

作者: ngugg | 来源:发表于2018-10-23 22:35 被阅读12次

    https://medium.com/@sarunw/codable-in-swift-4-0-1a12e38599d8

    can it replace JSON encode/decode lib out there?

    • 它可以取代JSON编码/解码lib吗?

    After I watched WWDC 2017 and heard about Codable I’m thinking of replacing my current JSON encode/decoder in my projects or at least use it in a new one.

    • 在我观看WWDC 2017并听说Codable之后,我正在考虑在我的项目中替换当前的JSON编码/解码器,或者至少在新项目中使用它。

    I’m happy to see Apple finally come up with this encoder/decoder built into Swift standard lib, since its such a mandatory tasks nowdays and for me I haven’t seen a clear winner in this area. I try to avoid using third part library as much as possible, so I’m really excited to explore its possibility and limitation.

    • 我很高兴看到Apple终于推出了内置于Swift标准库中的这种编码器/解码器,因为它现在是如此强制性的任务,而且对于我来说,我还没有看到这个领域的明显赢家。 我尽量避免使用第三方库,所以我很高兴能够探索它的可能性和局限性。

    What I looking for in encode/decode?

    • 我在编码/解码中寻找什么?

    1. Swift optional type supported

    • 支持Swift可选类型

    The most important thing I need is a Swift optional type supported, this is very cruciel for me, without this it is a deal-breaker.

    • 我需要的最重要的是支持Swift可选类型,对我来说这是非常棘手的,如果没有它,这是一个交易破坏者。

    Luckily Codable support this. If you have following User Object.

    • 幸运的是Codable支持这一点。 如果您有以下用户对象。
    struct User: Codable {
        var firstName: String
        var lastName: String
        var middleName: String?
    }
    

    These JSON strings are valid.

    • 这些JSON字符串有效。
    {
        "firstName": "John",
        "lastName": "Doe",
        "middleName": null
    }
    {
        "firstName": "John",
        "lastName": "Doe"
    }
    

    2. Be able to rename properties

    • 能够重命名属性

    If you have ever work with REST API you will see that most JSON keys doesn’t use CamelCase naming, but snake_case. Codable also support rename property keys and its very easy to do so.

    • 如果您曾经使用REST API,您将看到大多数JSON密钥不使用CamelCase命名,而是使用snake_case。 Codable也支持重命名属性键,它很容易实现。

    All you need to do is adding a nested enumeration named CodingKeys that conforms to the CodingKey protocol.

    • 您需要做的就是添加一个符合CodingKey协议的名为CodingKeys的嵌套枚举。

    From above example we can rename it like this.

    • 从上面的例子我们可以像这样重命名它。
    struct User: Codable {
        var firstName: String
        var lastName: String
        var middleName: String?
        enum CodingKeys: String, CodingKey {
             case firstName = "first_name"
             case lastName = "last_name"
             case middleName = "middle_name"
        }
    }
    

    And you will be able to decode this JSON

    • 并且您将能够解码此JSON
    {
        "first_name": "John",
        "last_name": "Doe",
        "middle_name": null
    }
    {
        "first_name": "John",
        "last_name": "Doe"
    }
    

    3. Custom mapping between JSON and Swift structure.

    • JSON和Swift结构之间的自定义映射。

    There are cases where we have no control over how JSON look like, be able to have different Swift structure than JSON is nice-to-have feature.

    • 在某些情况下,我们无法控制JSON的外观,能够拥有与JSON不同的Swift结构,这是一个很好的功能。

    I will test on 2 common cases. 我将测试2种常见情况

    1. Flatten out JSON nested property.
    • 展平JSON嵌套属性。
    1. Make nested structure from flat JSON.
    • 从平面JSON创建嵌套结构。

    4. Flatten out JSON

    • 展平JSON

    Let say you have User JSON that contain nested billingAddress property.

    • 假设您有User JSON包含嵌套的billingAddress属性。
    {
        "name": "John",
        "billingAddress": {
            "district": "District",
            "subDistrict": "Sub District",
            "country": "Country",
            "postalCode": "Postal Code"
        }
    }
    

    But somehow you want to layout Swift User like this.

    • 但不知何故,你想要像这样布局Swift用户。
    struct User: Codable {
        var name: String
        var district: String
        var subDistrict: String
        var country: String
        var postalCode: String
    }
    

    You need to define two enumerations that each list the complete set of coding keys used on a particular level.

    • 您需要定义两个枚举,每个枚举列出在特定级别上使用的完整编码密钥集。
    struct User: Codable {
        ....
        enum CodingKeys: String, CodingKey {
            case name
            case billingAddress
        }
        enum BillingAddressKeys: String, CodingKey {
            case district
            case subDistrict
            case country
            case postalCode
        }
    }
    

    Since this isn’t direct mapping we need to implementing Decodable's required initializer, init(from:):

    • 由于这不是直接映射,我们需要实现Decodable所需的初始化器init(from :):
    init(from decoder: Decoder) throws {
       let values = try decoder.container(keyedBy: CodingKeys.self)
       name = try values.decode(String.self, forKey: .name)
       let billingAddress = try values.nestedContainer(keyedBy:     BillingAddressKeys.self, forKey: .billingAddress)
       district = try billingAddress.decode(String.self, forKey: .district)
       subDistrict = try billingAddress.decode(String.self, forKey: .subDistrict)
       country = try billingAddress.decode(String.self, forKey: .country)
       postalCode = try billingAddress.decode(String.self, forKey: .postalCode)
    }
    

    And same apply to Encodable protocol, a custom encode(to:):

    • 同样适用于Encodable协议,自定义编码(至:):
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        var billingAddress = container.nestedContainer(keyedBy: BillingAddressKeys.self, forKey: .billingAddress)
        try billingAddress.encode(district, forKey: .district)
        try billingAddress.encode(subDistrict, forKey: .subDistrict)
        try billingAddress.encode(country, forKey: .country)
        try billingAddress.encode(postalCode, forKey: .postalCode)
    }
    

    5. Nested structure

    • 嵌套结构

    This is opposite of what we just did, we got JSON like this.

    • 这与我们刚刚做的相反,我们得到了这样的JSON。
    {
        "name": "John",
        "district": "District",
        "subDistrict": "Sub District",
        "country": "Country",
        "postalCode": "Postal Code"
    }
    

    And want this Swift structure

    • 并希望这个Swift结构
    struct User: Codable {
        var name: String
        var billingAddress: BillingAddress
    }
    struct BillingAddress: Codable {
        var district: String
        var subDistrict: String
        var country: String
        var postalCode: String
    }
    

    Following are what we need to implement

    • 以下是我们需要实施的内容
    struct User: Codable {
        ....
        enum CodingKeys: String, CodingKey {
            case name
            case billingAddress
            case district
            case subDistrict
            case country
            case postalCode
        }
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        billingAddress = try BillingAddress(from: decoder)
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)    
        try container.encode(name, forKey: .name)
        try container.encode(billingAddress.district, forKey: .district)
        try container.encode(billingAddress.subDistrict, forKey: .subDistrict)
        try container.encode(billingAddress.country, forKey: .country)
        try container.encode(billingAddress.postalCode, forKey: .postalCode)
    }
    
    

    Conclusion

    Codable pass all my criteria, it can do what I needed with easy to understand syntax. The only aspect that I didn’t touch is performance (I think it would be good). My conclusion is I definitely use it for my next project.

    • Codable通过了我的所有标准,它可以通过易于理解的语法完成我需要的工作。 我没有触及的唯一方面是性能(我认为这会很好)。 我的结论是我肯定将它用于我的下一个项目。

    相关文章

      网友评论

          本文标题:Codable in Swift 4.0

          本文链接:https://www.haomeiwen.com/subject/veezzftx.html