我已经为我的项目中的一些类实现了自定义JSON解码.我已经设置了常用的CodingKeys枚举,并实现了自定义的编码和解码函数.一切正常.
但是我还为解码过程实现了一些方便的函数,这些函数可以捕获JSONDecoder的KeyedDecodingContainer抛出的任何错误,并返回一些正常的结果.因为这些函数不需要在类之间变化,所以我想将它们移出类,但大多数示例将编码键定义为类中的硬编码枚举.
下面是要解码的类:
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
}
}
}
I want to move those safeDecode methods out of this class and into a general utility namespace. But that means I can't hard-code the coding keys as an enum in the class, so I need to pass them in as an array or dictionary. It seems like it should be simple, but thus far I haven't seen a succinct solution. #3 in this post seems close, but I don't really understand some of the logic: How do I use custom keys with Swift 4's Decodable protocol?
"safeDecode"函数的基本原理是,如果任何值丢失或为nil,解码对象将完全失败,这是完全可能的,因为这些列在我的数据库中是可为nullable的.为了防止没有方便的功能,我想我必须在一个单独的do/catch对中 for each 成员进行解码try .非常乏味但我并不知道你在try ?语法来逐行捕获此内容.因此,现在我只需要布尔帮助器来处理不同数据库的布尔类型.我把它放在一个KeyedDecodingContainer扩展中,就像@Alexander善意建议的那样.