Detailed explanation of Codable improvements in Swift 4.1

  • 2020-06-07 05:22:19
  • OfStack

preface

Among the many improvements Apple has made in Swift 4.0, my personal favorite is the emergence of the Codable protocol. It lets Swift come with the mapping and transformation capabilities of JSON, XML structured data, and Model.

The most common usage scenario for Codable is when APP initiates a network request and we convert the JSON data that the server responds to into the corresponding Model entity. The Codable default data transformation implementation may no longer be appropriate because the server-side programming specification may differ from the client-side programming specification. For example, the server might use a serpentine name while the client USES a hump. At this point, we need to implement the mapping on the client side.


struct Mac: Codable {
 var name: String
 var screenSize: Int
 var cpuCount: Int
}

let jsonString = """
[
 {
 "name": "MacBook Pro",
  "screen_size": 15,
  "cpu_count": 4
 },
 {
  "name": "iMac Pro",
  "screen_size": 27,
  "cpu_count": 18
 }
]
"""
let jsonData = Data(jsonString.utf8)
let decoder = JSONDecoder()
do {
 let macs = try decoder.decode([Mac].self, from: jsonData)
 print(macs)
} catch {
 print(error.localizedDescription)
}

The appeal code does not perform the desired decoding operation because the default implementation of Codable does not map the snake variable name to the corresponding hump attribute. Therefore, in Swift 4.0, we need to make some modifications to Mac:


struct Mac: Codable {
 var name: String
 var screenSize: Int
 var cpuCount: Int

 enum CodingKeys : String, CodingKey {
   case name
   case screenSize = "screen_size"
   case cpuCount = "cpu_count"
 }
}

Fortunately, Swift 4.1 improves on this. We can now decode between different programming specifications by setting keyDecodingStrategy to JSONDecoder. Correspondingly, JSONEncoder also has an keyEncodingStrategy attribute for coding operations between different programming specifications. Therefore, the appeal code can be simplified as follows:


struct Mac: Codable {
 var name: String
 var screenSize: Int
 var cpuCount: Int
}

let jsonString = """
[
 {
 "name": "MacBook Pro",
  "screen_size": 15,
  "cpu_count": 4
 },
 {
  "name": "iMac Pro",
  "screen_size": 27,
  "cpu_count": 18
 }
]
"""
let jsonData = Data(jsonString.utf8)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

do {
 let macs = try decoder.decode([Mac].self, from: jsonData)
 print(macs)
} catch {
 print(error.localizedDescription)
}

The code is also very simple if you want to do the reverse conversion:


let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let encoded = try encoder.encode(macs)

Of course, we can also customize the implementation of the transformation policy to fulfill some specific requirements. The specific usage can refer to the code

conclusion


Related articles: