如何将CodingKeys以数组而非枚举形式传入类外函数?
问题背景与需求
我在项目中为部分类实现了自定义JSON解码,已配置常规的CodingKeys枚举并实现了自定义编码、解码函数,功能运行正常。
但我还实现了几个解码过程的便捷函数,用于捕获JSONDecoder的KeyedDecodingContainer抛出的错误并返回合理值。由于这些函数无需在不同类间变更,我希望将其移至类外,但多数示例都将编码键硬编码为类内枚举。
补充说明:成员未设为可选类型是有合理原因的——SwiftUI中无法绑定可选类型,因此无法在编辑UI中显示该结构。
待解码的User类代码
class User : Equatable, Codable { var ID: String = "" var pw: String = "" var username: String = "" var firstName: String = "" var lastName: String = "" var EMail: String = "" var phoneNbr: String = "" var avatarURL: String = "" var mediaServiceID: String = "" var validated: Bool = false // E-mail is confirmed. // Equatable static func == (lhs: User, rhs: User) -> Bool { return lhs.ID == rhs.ID } // Codable enum CodingKeys: String, CodingKey { case ID = "ID" case pw = "pw" case username = "username" case firstName = "firstName" case lastName = "lastName" case EMail = "EMail" case phoneNbr = "phoneNbr" case avatarURL = "avatarURL" case mediaServiceID = "mediaServiceID" case validated = "validated" } required init(from decoder: Decoder) throws { var container: KeyedDecodingContainer<CodingKeys> do { container = try decoder.container(keyedBy: CodingKeys.self) } ID = safeStringDecode(container: container, forKey: .ID) pw = safeStringDecode(container: container, forKey: .pw) username = safeStringDecode(container: container, forKey: .username) firstName = safeStringDecode(container: container, forKey: .firstName) lastName = safeStringDecode(container: container, forKey: .lastName) EMail = safeStringDecode(container: container, forKey: .EMail) phoneNbr = safeStringDecode(container: container, forKey: .phoneNbr) avatarURL = safeStringDecode(container: container, forKey: .avatarURL) mediaServiceID = safeStringDecode(container: container, forKey: .mediaServiceID) validated = safeBoolDecode(container: container, forKey: .validated) } func safeStringDecode(container: KeyedDecodingContainer<CodingKeys>, forKey: CodingKeys) -> String { var result: String do { result = try container.decode(String.self, forKey: forKey) } catch { result = "" } return result } func safeBoolDecode(container: KeyedDecodingContainer<CodingKeys>, forKey: CodingKeys) -> Bool { // First try int, because that's what MySQL/MariaDB return for bools. var result: Int do { result = try container.decode(Int.self, forKey: forKey) return result == 1 } catch { // Let's see if it's a 'true'/'false' string. var stringResult: String do { stringResult = try container.decode(String.self, forKey: forKey) return stringResult == "true" } catch { return false } } } }
核心需求与后续思考
我希望将这些safeDecode方法移至通用工具命名空间中,但这意味着无法将编码键硬编码为类内枚举,因此需要将其以数组或字典形式传入。这看似简单,但目前我尚未找到简洁的解决方案。
实现safeDecode函数的原因是:若任何值缺失或为nil,对象解码会完全失败,而这种情况在我的数据库中完全可能发生,因为这些列是可空的。若没有这些便捷函数,我原本需要为每个成员的解码尝试单独编写do/catch代码块,这极其繁琐。但我之前不知道可以用try?语法逐行捕获错误。因此现在我仅需要布尔值助手函数来处理不同数据库的布尔类型。按照建议,我将其放在了KeyedDecodingContainer扩展中。
内容的提问来源于stack exchange,提问作者Oscar
相关产品推荐
相关产品推荐

