如何在Swift 4的Decodable协议中使用自定义键?

如何在Swift 4的Decodable协议中使用自定义键?,第1张

如何在Swift 4的Decodable协议中使用自定义键? 手动自定义编码

在您的示例中,

Codable
由于所有属性也都符合,因此您将获得自动生成的符合
Codable
。这种一致性会自动创建一个仅与属性名称相对应的密钥类型,然后将其用于对单个密钥容器进行编码/解码

但是,这种自动生成的一致性的一个 真正 巧妙的功能是,如果您

enum
在称为“
CodingKeys

的类型中定义一个嵌套(或使用
typealias
具有此名称的a)来符合
CodingKey
协议,则Swift将自动将
用作键类型。因此,这使您可以轻松自定义用于对属性进行编码/解码的键。

因此,这意味着您可以说:

struct Address : Codable {    var street: String    var zip: String    var city: String    var state: String    private enum CodingKeys : String, CodingKey {        case street, zip = "zip_pre", city, state    }}

枚举案例名称需要与属性名称匹配,并且这些案例的原始值需要与您要编码/解码的键匹配(除非另有指定,否则

String
枚举的原始值将与案例名称相同)。因此,
zip
现在将使用key
对属性进行编码/解码
"zip_pre"

有关自动生成

Encodable
/
Decodable
一致性的确切规则,请参见演进提案(重点是我的):

除了的自动

CodingKey
需求综合外
enums
Encodable
Decodable
需求还可以针对某些类型自动综合:

1.
符合

Encodable
所有属性的类型将
Encodable
获得自动生成的
String
支持的
CodingKey
枚举,将枚举属性映射到案例名称。对于
Decodable
所有属性都相同的类型也是如此
Decodable

  1. 属于(1)的 类型

    CodingKey

    enum``CodingKeys``typealias``Encodable``Decodable
    - 以及手动提供类型
    (名称为 ,直接或通过a )将其案例 按名称 一对一映射到 / 属性的类型 -
    使用这些属性和键自动进行合并,
    init(from:)
    enpre(to:)
    在适当时进行合并

  2. 落入类型既不(1)也没有(2)将具有如果需要的话提供一个自定义的密钥类型和提供它们自己的

    init(from:)

    enpre(to:)
    ,如适当

编码示例:

import Foundationlet address = Address(street: "Apple Bay Street", zip: "94608",city: "Emeryville", state: "California")do {    let enpred = try JSonEnprer().enpre(address)    print(String(decoding: enpred, as: UTF8.self))} catch {    print(error)}//{"state":"California","street":"Apple Bay Street","zip_pre":"94608","city":"Emeryville"}

解码示例:

// using the """ multi-line string literal here, as introduced in SE-0168,// to avoid escaping the quotation markslet jsonString = """{"state":"California","street":"Apple Bay Street","zip_pre":"94608","city":"Emeryville"}"""do {    let depred = try JSonDeprer().depre(Address.self, from: Data(jsonString.utf8))    print(depred)} catch {    print(error)}// Address(street: "Apple Bay Street", zip: "94608",// city: "Emeryville", state: "California")

属性名称的自动
snake_case
JSON键
camelCase

在雨燕4.1,如果您重命名

zip
属性
zipCode
,你可以利用关键的编码/解码上的策略
JSONEnprer
,并
JSONDeprer
以自动转换之间的编码键
camelCase
snake_case

编码示例:

import Foundationstruct Address : Codable {  var street: String  var zipCode: String  var city: String  var state: String}let address = Address(street: "Apple Bay Street", zipCode: "94608",city: "Emeryville", state: "California")do {  let enprer = JSonEnprer()  **enprer.keyEncodingStrategy = .convertToSnakeCase**  let enpred = try enprer.enpre(address)  print(String(decoding: enpred, as: UTF8.self))} catch {  print(error)}//{"state":"California","street":"Apple Bay Street","zip_pre":"94608","city":"Emeryville"}

解码示例:

let jsonString = """{"state":"California","street":"Apple Bay Street","zip_pre":"94608","city":"Emeryville"}"""do {  let deprer = JSonDeprer()  **deprer.keyDecodingStrategy = .convertFromSnakeCase**  let depred = try deprer.depre(Address.self, from: Data(jsonString.utf8))  print(depred)} catch {  print(error)}// Address(street: "Apple Bay Street", zipCode: "94608",// city: "Emeryville", state: "California")

但是,有关此策略的重要注意事项是,它无法使用首字母缩写词或首字母缩写来循环某些属性名称,根据Swift
API设计指南,这些属性名称应统一使用大写或小写(取决于位置) )。

例如,名为的属性

someURL
将使用键进行编码
some_url
,但是在解码时,它将转换为
someUrl

要解决此问题,您必须手动将该属性的编码键指定为解码器期望的字符串,例如,

someUrl
在这种情况下(
some_url
编码器仍将其转换为):

struct S : Codable {  private enum CodingKeys : String, CodingKey {    case someURL = "someUrl", someOtherProperty  }  var someURL: String  var someOtherProperty: String}

(这并不能严格回答您的特定问题,但是鉴于此问答的典型性质,我认为值得考虑)

自定义自动JSON密钥映射

在雨燕4.1,您可以利用自定义按键编码/解码上的策略

JSONEnprer
JSONDeprer
,使您可以提供一个自定义函数映射的编码键。

您提供的函数采用

[CodingKey]
,代表编码/解码中当前点的编码路径(在大多数情况下,您只需要考虑最后一个元素;即当前键)。该函数返回一个
CodingKey
,它将替换此数组中的最后一个键。

例如,属性名称的

UpperCamelCase
JSON键
lowerCamelCase

import Foundation// wrapper to allow us to substitute our mapped string keys.struct AnyCodingKey : CodingKey {  var stringValue: String  var intValue: Int?  init(_ base: CodingKey) {    self.init(stringValue: base.stringValue, intValue: base.intValue)  }  init(stringValue: String) {    self.stringValue = stringValue  }  init(intValue: Int) {    self.stringValue = "(intValue)"    self.intValue = intValue  }  init(stringValue: String, intValue: Int?) {    self.stringValue = stringValue    self.intValue = intValue  }}

extension JSONEnprer.KeyEncodingStrategy {  static var convertToUpperCamelCase: JSONEnprer.KeyEncodingStrategy {    return .custom { codingKeys in      var key = AnyCodingKey(codingKeys.last!)      // uppercase first letter      if let firstChar = key.stringValue.first {        let i = key.stringValue.startIndex        key.stringValue.replaceSubrange(          i ... i, with: String(firstChar).uppercased()        )      }      return key    }  }}

extension JSONDeprer.KeyDecodingStrategy {  static var convertFromUpperCamelCase: JSONDeprer.KeyDecodingStrategy {    return .custom { codingKeys in      var key = AnyCodingKey(codingKeys.last!)      // lowercase first letter      if let firstChar = key.stringValue.first {        let i = key.stringValue.startIndex        key.stringValue.replaceSubrange(          i ... i, with: String(firstChar).lowercased()        )      }      return key    }  }}

您现在可以使用以下

.convertToUpperCamelCase
关键策略进行编码:

let address = Address(street: "Apple Bay Street", zipCode: "94608",city: "Emeryville", state: "California")do {  let enprer = JSonEnprer()  enprer.keyEncodingStrategy = .convertToUpperCamelCase  let enpred = try enprer.enpre(address)  print(String(decoding: enpred, as: UTF8.self))} catch {  print(error)}//{"Street":"Apple Bay Street","City":"Emeryville","State":"California","ZipCode":"94608"}

并采用以下

.convertFromUpperCamelCase
关键策略进行解码:

let jsonString = """{"Street":"Apple Bay Street","City":"Emeryville","State":"California","ZipCode":"94608"}"""do {  let deprer = JSonDeprer()  deprer.keyDecodingStrategy = .convertFromUpperCamelCase  let depred = try deprer.depre(Address.self, from: Data(jsonString.utf8))  print(depred)} catch {  print(error)}// Address(street: "Apple Bay Street", zipCode: "94608",// city: "Emeryville", state: "California")


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5126481.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-17
下一篇 2022-11-17

发表评论

登录后才能评论

评论列表(0条)

保存