Codable in Swift 4.0

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通过了我的所有标准,它可以通过易于理解的语法完成我需要的工作。 我没有触及的唯一方面是性能(我认为这会很好)。 我的结论是我肯定将它用于我的下一个项目。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351