首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有更短的方法来声明CodingKeys?

是否有更短的方法来声明CodingKeys?
EN

Stack Overflow用户
提问于 2022-06-26 10:10:36
回答 2查看 70关注 0票数 1

假设您有一个API响应模型的struct。假设它有50个成员。然而,5-7个成员是非标准的套管,你可以有AUsernAme_BTmember,但其余都是蛇案例credit_scorestatus_code

而不是像这样写所有的成员:

代码语言:javascript
复制
struct MyStruct {
  let aUserName: String
  // +50 more...

  private enum CodingKeys: String, CodingKey {
    case aUserName = "AUsernAme"
    // +50 more...
  }
}

我们有办法写成这样吗?

代码语言:javascript
复制
struct MyStruct {
  @CodingKey("AUsernAme") let aUserName: String
  let creditScore: Int
  // +50 more ...
}

编辑:--我想现在的Swift版本是不可能的,但是有人知道这是否会被包含在Swift的未来版本中吗?

EN

回答 2

Stack Overflow用户

发布于 2022-06-26 16:00:01

Sweeper提供的解决方案是解决您的问题的一个很好的解决方案,但IMO可能会对您的问题和将要阅读此代码的下一个开发人员显示出极大的复杂性。

如果我是你,为了简单起见,我只会坚持编写所有的CodingKeys。如果您的担心是编写了大量的案例,那么您可以在一行中编写所有不需要自定义键的情况,只需在新行中添加带有异常/非标准大小写的键:

代码语言:javascript
复制
case property1, property2, property3, property4, property5...
case property50 = "_property50"

既然你提到剩下的都是蛇箱,还不确定你是否知道,但我们有JSONDecoder.KeyDecodingStrategy.convertFromSnakeCase

希望这能帮助` `tol!:)

票数 1
EN

Stack Overflow用户

发布于 2022-06-26 11:10:23

不如在解码之前设置一个自定义keyDecodingStrategy如何?

代码语言:javascript
复制
struct AnyCodingKey: CodingKey, Hashable {
    var stringValue: String

    init(stringValue: String) {
        self.stringValue = stringValue
    }

    var intValue: Int?

    init(intValue: Int) {
        self.intValue = intValue
        self.stringValue = "\(intValue)"
    }
}

let mapping = [
    "AUsernAme": "aUserName",
    // other mappings...
]

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .custom({ codingPath in
    let key = codingPath[0].stringValue
    guard let mapped = mapping[key] else { return codingPath.last! }
    return AnyCodingKey(stringValue: mapped)
})

这假设您的JSON有一个单一的平面结构。您可以将其转换为一个扩展:

代码语言:javascript
复制
extension JSONDecoder.KeyDecodingStrategy {
    static func mappingRootKeys(_ dict: [String: String]) -> JSONDecoder.KeyDecodingStrategy {
        return .custom { codingPath in
            let key = codingPath[0].stringValue
            guard let mapped = dict[key] else { return codingPath.last! }
            return AnyCodingKey(stringValue: mapped)
        }
    }
}

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .mappingRootKeys(mapping)

如果JSON有更多级别,则可以将字典的类型更改为[JSONPath: String],其中JSONPath是可以在嵌套JSON中创建的表示键的类型。然后添加一些代码,将编码路径(这只是一个编码键数组)转换为JSONPath。这应该不难自己写。

一个简单的方法是只使用[AnyCodingKey]作为JSONPath,但是还有很多其他的方法,我鼓励您尝试并找到您最喜欢的方法。

代码语言:javascript
复制
typealias JSONPath = [AnyCodingKey]

extension AnyCodingKey {
    init(codingKey: CodingKey) {
        if let int = codingKey.intValue {
            self.init(intValue: int)
        } else {
            self.init(stringValue: codingKey.stringValue)
        }
    }
}


extension JSONDecoder.KeyDecodingStrategy {
    static func mappingRootKeys(_ dict: [JSONPath: String]) -> JSONDecoder.KeyDecodingStrategy {
        return .custom { codingPath in
            guard let mapped = dict[codingPath.map(AnyCodingKey.init(codingKey:))] else { return codingPath.last! }
            return AnyCodingKey(stringValue: mapped)
        }
    }
}

let mapping = [
    [AnyCodingKey(stringValue: "AUsernAme")]: "aUserName"
]

不可能为此使用属性包装器。您的属性包装器@CodingKey("AUsernAme") let aUserName: String将被编译成如下所示(按照这里):

代码语言:javascript
复制
private var _aUserName: CodingKey<String> = CodingKey("AUsernAme") 
var aUserName: String {
    get { _aUserName.wrappedValue }
    set { _aUserName.wrappedValue = newValue }
}

这方面有两个主要问题:

  • 假设您不想为init(from:)中的所有50+属性编写MyStruct,代码将被合成来解码,并分配给它的_aUserName属性。您只能控制CodingKey属性包装器的CodingKey初始化器,并且不能在其中对MyStruct进行任何解码。如果MyStruct包含在另一个结构中: 结构AnotherStruct:可解码{ let myStruct: MyStruct } 然后,您确实可以通过使用属性包装器对myStruct进行标记来控制用于解码它的编码键。在解码过程中,您可以通过实现属性包装器的init(from:)来做您想做的任何事情,这就引出了第二个问题:
  • 传递给CodingKey属性包装器的编码键是通过表单init(_ key: String)的初始化项传递的。但是您可以通过初始化器init(from decoder: Decoder)来控制解码,因为这就是在对结构进行解码时将调用的内容。换句话说,您无法将密钥映射发送到属性包装器。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72760627

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档