如何解码多个 Decodable Swift 中的单个异常 属性?
How to decode single unusual property among many Decodable Swift?
我有一个符合 Decodable 的结构。它有 50 个 String 属性,只有一个 Bool。该 bool 来自服务器,如字符串“false”/“true”或有时像整数 0/1,因此无法从框中解码。我怎样才能让它解码而不是编写所有 50 个字符串属性的大量手动解码?也许以某种方式覆盖 Bool 的 decodeIfPresent,但我无法使其工作。
我如何避免创建 init 并手动解码所有内容并只处理那个 Bool?如果可能,不计算 属性。
struct Response: Decodable {
var s1: String
var s2: String
var s3: String
//...........
var s50: String
var b1: Bool
var b2: Bool
}
这里是json例子:
{
"s1":"string"
"s2":"string"
"s3":"string"
//..........
"s50":"string"
"b1":"true"
"b2":"0"
}
试过这个但不起作用(((
extension KeyedDecodingContainer { //Doesn't work, no execution
func decodeIfPresent(_ type: Bool.Type, forKey key: K) throws -> Bool {
return try! self.decodeIfPresent(Bool.self, forKey: key)
}
func decodeIfPresent(_ type: Bool.Type, forKey key: K) throws -> Bool? {
return try? self.decodeIfPresent(Bool.self, forKey: key)
}
}
解决这个问题的一种方法是编写一个 属性 包装器来处理自定义解码,如下所示:
@propertyWrapper
struct FunnyBool: Decodable {
var wrappedValue: Bool
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let value = try? container.decode(Bool.self) {
wrappedValue = value
}
else if
let string = try? container.decode(String.self),
let value = Bool(string)
{
wrappedValue = value
}
else if
let int = try? container.decode(Int.self),
let value = int == 0 ? false : int == 1 ? true : nil
{
wrappedValue = value
}
else {
// Default...
wrappedValue = false
}
}
}
这样使用:
struct Response: Decodable {
var s1: String
var s2: String
@FunnyBool var b: Bool
}
let json = #"{ "s1": "hello", "s2": "world", "b": 1 }"#
let response = try! JSONDecoder().decode(Response.self, from: json.data(using: .utf8)!)
dump(response)
游乐场输出:
▿ __lldb_expr_11.Response
- s1: "hello"
- s2: "world"
▿ _b: __lldb_expr_11.FunnyBool
- wrappedValue: true
我有一个符合 Decodable 的结构。它有 50 个 String 属性,只有一个 Bool。该 bool 来自服务器,如字符串“false”/“true”或有时像整数 0/1,因此无法从框中解码。我怎样才能让它解码而不是编写所有 50 个字符串属性的大量手动解码?也许以某种方式覆盖 Bool 的 decodeIfPresent,但我无法使其工作。 我如何避免创建 init 并手动解码所有内容并只处理那个 Bool?如果可能,不计算 属性。
struct Response: Decodable {
var s1: String
var s2: String
var s3: String
//...........
var s50: String
var b1: Bool
var b2: Bool
}
这里是json例子:
{
"s1":"string"
"s2":"string"
"s3":"string"
//..........
"s50":"string"
"b1":"true"
"b2":"0"
}
试过这个但不起作用(((
extension KeyedDecodingContainer { //Doesn't work, no execution
func decodeIfPresent(_ type: Bool.Type, forKey key: K) throws -> Bool {
return try! self.decodeIfPresent(Bool.self, forKey: key)
}
func decodeIfPresent(_ type: Bool.Type, forKey key: K) throws -> Bool? {
return try? self.decodeIfPresent(Bool.self, forKey: key)
}
}
解决这个问题的一种方法是编写一个 属性 包装器来处理自定义解码,如下所示:
@propertyWrapper
struct FunnyBool: Decodable {
var wrappedValue: Bool
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let value = try? container.decode(Bool.self) {
wrappedValue = value
}
else if
let string = try? container.decode(String.self),
let value = Bool(string)
{
wrappedValue = value
}
else if
let int = try? container.decode(Int.self),
let value = int == 0 ? false : int == 1 ? true : nil
{
wrappedValue = value
}
else {
// Default...
wrappedValue = false
}
}
}
这样使用:
struct Response: Decodable {
var s1: String
var s2: String
@FunnyBool var b: Bool
}
let json = #"{ "s1": "hello", "s2": "world", "b": 1 }"#
let response = try! JSONDecoder().decode(Response.self, from: json.data(using: .utf8)!)
dump(response)
游乐场输出:
▿ __lldb_expr_11.Response
- s1: "hello"
- s2: "world"
▿ _b: __lldb_expr_11.FunnyBool
- wrappedValue: true