Swift 4 decodable var 可以是 Bool 或自定义类型
Swift 4 decodable var can be either Bool or custom type
我已经为此苦苦挣扎了一段时间。我有一个从 API 调用中获得的 JSON,但它有一个键,该键可以为假或 return 为真时的值。
像这样:
{
"id": 550,
"favorite": true,
"rated": {
"value": 8
},
"watchlist": false
}
或者这个:
{
"id": 550,
"favorite": true,
"rated": false,
"watchlist": false
}
我试过这样解码:
struct AccountState: Decodable {
var id: Int?
var favorite: Bool?
var rated: CustomValue
var watchlist: Bool?
}
struct RatingValue: Decodable {
var value: Double?
}
enum CustomValue: Decodable {
case bool(Bool)
case rating(RatingValue)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let bool = try? container.decode(Bool.self) {
self = .bool(bool)
} else if let rating = try? container.decode(RatingValue.self) {
self = .rating(rating)
} else {
let context = DecodingError.Context(codingPath: container.codingPath, debugDescription: "Unknown type")
throw DecodingError.dataCorrupted(context)
}
}
}
在ViewController中:
func dowloadAndDecodeData() {
let url...
...
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
guard let accountState = try? decoder.decode(AccountState.self, from: data) else {
print("error")
return
}
print(accountState)
}
在控制台中,我可以看到 JSON 内容已被正确解析(returning 为 false 或值(如果存在)。
问题是:如何从代码中访问这个值?由于 "rated" 是 "CustomValue" 类型,我不能像通常那样使用 accountState.rated.value
。
要访问类似 CustomValue
的内容(enum
个具有关联值的案例),您需要使用 switch-case 或 if-case。
switch accountState.rated {
case .rating(let ratingValue):
print(ratingValue.value)
case .bool(let boolValue):
print(boolValue);
}
否则,您可以为 CustomValue
定义一个简单的扩展名:
extension CustomValue {
var value: Double? {
switch self {
case .rating(let ratingValue):
return ratingValue.value
case .bool: //### in case .bool, return nil
return nil
}
}
}
您可以简单地访问它:
if let value = accountState.rated.value {
print(value)
}
我遇到了同样的问题,我已经 属性 调用了 Any。所以我可以将它转换为所需的数据类型。
在这里查看我的回答。
我没有添加 bool 类型,但它会 100% 解决你的问题,如果你需要进一步的帮助,请告诉我
在您的 CustomValue class.
中添加以下 属性 之前阅读我的回答
var any:Any{
get{
switch self {
case .bool(let value):
return value
}
}
}
我已经为此苦苦挣扎了一段时间。我有一个从 API 调用中获得的 JSON,但它有一个键,该键可以为假或 return 为真时的值。
像这样:
{
"id": 550,
"favorite": true,
"rated": {
"value": 8
},
"watchlist": false
}
或者这个:
{
"id": 550,
"favorite": true,
"rated": false,
"watchlist": false
}
我试过这样解码:
struct AccountState: Decodable {
var id: Int?
var favorite: Bool?
var rated: CustomValue
var watchlist: Bool?
}
struct RatingValue: Decodable {
var value: Double?
}
enum CustomValue: Decodable {
case bool(Bool)
case rating(RatingValue)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let bool = try? container.decode(Bool.self) {
self = .bool(bool)
} else if let rating = try? container.decode(RatingValue.self) {
self = .rating(rating)
} else {
let context = DecodingError.Context(codingPath: container.codingPath, debugDescription: "Unknown type")
throw DecodingError.dataCorrupted(context)
}
}
}
在ViewController中:
func dowloadAndDecodeData() {
let url...
...
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
guard let accountState = try? decoder.decode(AccountState.self, from: data) else {
print("error")
return
}
print(accountState)
}
在控制台中,我可以看到 JSON 内容已被正确解析(returning 为 false 或值(如果存在)。
问题是:如何从代码中访问这个值?由于 "rated" 是 "CustomValue" 类型,我不能像通常那样使用 accountState.rated.value
。
要访问类似 CustomValue
的内容(enum
个具有关联值的案例),您需要使用 switch-case 或 if-case。
switch accountState.rated {
case .rating(let ratingValue):
print(ratingValue.value)
case .bool(let boolValue):
print(boolValue);
}
否则,您可以为 CustomValue
定义一个简单的扩展名:
extension CustomValue {
var value: Double? {
switch self {
case .rating(let ratingValue):
return ratingValue.value
case .bool: //### in case .bool, return nil
return nil
}
}
}
您可以简单地访问它:
if let value = accountState.rated.value {
print(value)
}
我遇到了同样的问题,我已经 属性 调用了 Any。所以我可以将它转换为所需的数据类型。
在这里查看我的回答。
我没有添加 bool 类型,但它会 100% 解决你的问题,如果你需要进一步的帮助,请告诉我
在您的 CustomValue class.
中添加以下 属性 之前阅读我的回答 var any:Any{
get{
switch self {
case .bool(let value):
return value
}
}
}