与枚举类型 属性 的可解码一致性
Decodable conformance with property of enum type
我有这个枚举:
enum DealStatus:String {
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
和结构:
struct ActiveDeals: Decodable {
let keyword: String
let bookingType: String
let expiryDate: Int
let createdAt: Int?
let shopLocation: String?
let dealImages: [DealImages]?
let dealStatus: String?
let startingDate: Int?
}
在结构中,我试图将枚举分配为 dealStatus
的类型,如下所示:
struct ActiveDeals: Decodable {
let keyword: String
let bookingType: String
let expiryDate: Int
let createdAt: Int?
let shopLocation: String?
let dealImages: [DealImages]?
let dealStatus: DealStatus
let startingDate: Int?
}
但是我遇到了一些编译器错误:
Type 'ActiveDeals' does not conform to protocol 'Decodable'
Protocol requires initializer 'init(from:)' with type 'Decodable'
(Swift.Decodable)
Cannot automatically synthesize 'Decodable'
because 'DealStatus' does not conform to 'Decodable'
错误表示 class 的某些属性不符合 Decodable 协议。
将 Decodable 一致性添加到您的枚举中,应该没问题。
extension DealStatus: Decodable { }
问题是 Swift 可以自动合成 Decodable
需要的方法只有当一个结构的所有属性也是 Decodable
而你的枚举不是 Decodable
.
刚刚在操场上试了一下,看来你可以让你的枚举 Decodable
只需声明它是 并且 Swift 会自动为您综合方法。即
enum DealStatus:String, Decodable
// ^^^^^^^^^ This is all you need
{
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
根据 Federico Zanetello 在他的 post Swift 4 Decodable: Beyond The Basics 上的说法,如果您需要解析基元的子集(字符串、数字、布尔值等),Codable 和 Decobable 协议可以正常工作。
根据您的情况,只需使 DealStatus 符合 Decodable(如
JeremyP) 应该可以解决你的问题。您可以检查 Playgrounds 创建您自己的 JSON 数据并尝试解析它:
import UIKit
enum DealStatus: String, Decodable {
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
struct ActiveDeals: Decodable {
let keyword: String
let bookingType: String
let expiryDate: Int
let createdAt: Int?
let shopLocation: String?
let dealStatus: DealStatus
let startingDate: Int?
}
let json = """
{
"keyword": "Some keyword",
"bookingType": "A type",
"expiryDate": 123456,
"createdAt": null,
"shopLocation": null,
"dealStatus": "Declined",
"startingDate": 789456
}
""".data(using: .utf8)!
do {
let deal = try JSONDecoder().decode(ActiveDeals.self, from: json)
print(deal)
print(deal.dealStatus)
} catch {
print("error info: \(error)")
}
输出将是:
ActiveDeals(keyword: "Some keyword", bookingType: "A type", expiryDate: 123456, createdAt: nil, shopLocation: nil, dealStatus: __lldb_expr_61.DealStatus.DECLINED, startingDate: Optional(789456))
DECLINED
但是,要成为更好的程序员,您应该始终保持好奇心并尝试了解事物的原理,因此如果您对如何符合 Decodable 协议感兴趣(假设您需要自定义键、自定义错误或更多复杂的数据结构),你可以这样做:
import UIKit
enum DealStatus: String {
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
struct ActiveDeals {
let keyword: String
let bookingType: String
let expiryDate: Int
let createdAt: Int?
let shopLocation: String?
let dealStatus: DealStatus
let startingDate: Int?
}
extension ActiveDeals: Decodable {
enum StructKeys: String, CodingKey {
case keyword = "keyword"
case bookingType = "booking_type"
case expiryDate = "expiry_date"
case createdAt = "created_at"
case shopLocation = "shop_location"
case dealStatus = "deal_status"
case startingDate = "starting_date"
}
enum DecodingError: Error {
case dealStatus
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StructKeys.self)
let keyword = try container.decode(String.self, forKey: .keyword)
let bookingType = try container.decode(String.self, forKey: .bookingType)
let expiryDate = try container.decode(Int.self, forKey: .expiryDate)
let createdAt = try container.decode(Int?.self, forKey: .createdAt)
let shopLocation = try container.decode(String?.self, forKey: .shopLocation)
//Get deal status as a raw string and then convert to your custom enum
let dealStatusRaw = try container.decode(String.self, forKey: .dealStatus)
guard let dealStatus = DealStatus(rawValue: dealStatusRaw) else {
throw DecodingError.dealStatus
}
let startingDate = try container.decode(Int?.self, forKey: .startingDate)
self.init(keyword: keyword, bookingType: bookingType, expiryDate: expiryDate, createdAt: createdAt, shopLocation: shopLocation, dealStatus: dealStatus, startingDate: startingDate)
}
}
let json = """
{
"keyword": "Some keyword",
"booking_type": "A type",
"expiry_date": 123456,
"created_at": null,
"shop_location": null,
"deal_status": "Declined",
"starting_date": 789456
}
""".data(using: .utf8)!
do {
let deal = try JSONDecoder().decode(ActiveDeals.self, from: json)
print(deal)
print(deal.dealStatus)
} catch {
print("error info: \(error)")
}
在这种情况下,输出仍然相同:
ActiveDeals(keyword: "Some keyword", bookingType: "A type", expiryDate: 123456, createdAt: nil, shopLocation: nil, dealStatus: __lldb_expr_67.DealStatus.DECLINED, startingDate: Optional(789456))
DECLINED
我有这个枚举:
enum DealStatus:String {
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
和结构:
struct ActiveDeals: Decodable {
let keyword: String
let bookingType: String
let expiryDate: Int
let createdAt: Int?
let shopLocation: String?
let dealImages: [DealImages]?
let dealStatus: String?
let startingDate: Int?
}
在结构中,我试图将枚举分配为 dealStatus
的类型,如下所示:
struct ActiveDeals: Decodable {
let keyword: String
let bookingType: String
let expiryDate: Int
let createdAt: Int?
let shopLocation: String?
let dealImages: [DealImages]?
let dealStatus: DealStatus
let startingDate: Int?
}
但是我遇到了一些编译器错误:
Type 'ActiveDeals' does not conform to protocol 'Decodable'
Protocol requires initializer 'init(from:)' with type 'Decodable' (Swift.Decodable)
Cannot automatically synthesize 'Decodable' because 'DealStatus' does not conform to 'Decodable'
错误表示 class 的某些属性不符合 Decodable 协议。
将 Decodable 一致性添加到您的枚举中,应该没问题。
extension DealStatus: Decodable { }
问题是 Swift 可以自动合成 Decodable
需要的方法只有当一个结构的所有属性也是 Decodable
而你的枚举不是 Decodable
.
刚刚在操场上试了一下,看来你可以让你的枚举 Decodable
只需声明它是 并且 Swift 会自动为您综合方法。即
enum DealStatus:String, Decodable
// ^^^^^^^^^ This is all you need
{
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
根据 Federico Zanetello 在他的 post Swift 4 Decodable: Beyond The Basics 上的说法,如果您需要解析基元的子集(字符串、数字、布尔值等),Codable 和 Decobable 协议可以正常工作。
根据您的情况,只需使 DealStatus 符合 Decodable(如 JeremyP) 应该可以解决你的问题。您可以检查 Playgrounds 创建您自己的 JSON 数据并尝试解析它:
import UIKit
enum DealStatus: String, Decodable {
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
struct ActiveDeals: Decodable {
let keyword: String
let bookingType: String
let expiryDate: Int
let createdAt: Int?
let shopLocation: String?
let dealStatus: DealStatus
let startingDate: Int?
}
let json = """
{
"keyword": "Some keyword",
"bookingType": "A type",
"expiryDate": 123456,
"createdAt": null,
"shopLocation": null,
"dealStatus": "Declined",
"startingDate": 789456
}
""".data(using: .utf8)!
do {
let deal = try JSONDecoder().decode(ActiveDeals.self, from: json)
print(deal)
print(deal.dealStatus)
} catch {
print("error info: \(error)")
}
输出将是:
ActiveDeals(keyword: "Some keyword", bookingType: "A type", expiryDate: 123456, createdAt: nil, shopLocation: nil, dealStatus: __lldb_expr_61.DealStatus.DECLINED, startingDate: Optional(789456))
DECLINED
但是,要成为更好的程序员,您应该始终保持好奇心并尝试了解事物的原理,因此如果您对如何符合 Decodable 协议感兴趣(假设您需要自定义键、自定义错误或更多复杂的数据结构),你可以这样做:
import UIKit
enum DealStatus: String {
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
struct ActiveDeals {
let keyword: String
let bookingType: String
let expiryDate: Int
let createdAt: Int?
let shopLocation: String?
let dealStatus: DealStatus
let startingDate: Int?
}
extension ActiveDeals: Decodable {
enum StructKeys: String, CodingKey {
case keyword = "keyword"
case bookingType = "booking_type"
case expiryDate = "expiry_date"
case createdAt = "created_at"
case shopLocation = "shop_location"
case dealStatus = "deal_status"
case startingDate = "starting_date"
}
enum DecodingError: Error {
case dealStatus
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StructKeys.self)
let keyword = try container.decode(String.self, forKey: .keyword)
let bookingType = try container.decode(String.self, forKey: .bookingType)
let expiryDate = try container.decode(Int.self, forKey: .expiryDate)
let createdAt = try container.decode(Int?.self, forKey: .createdAt)
let shopLocation = try container.decode(String?.self, forKey: .shopLocation)
//Get deal status as a raw string and then convert to your custom enum
let dealStatusRaw = try container.decode(String.self, forKey: .dealStatus)
guard let dealStatus = DealStatus(rawValue: dealStatusRaw) else {
throw DecodingError.dealStatus
}
let startingDate = try container.decode(Int?.self, forKey: .startingDate)
self.init(keyword: keyword, bookingType: bookingType, expiryDate: expiryDate, createdAt: createdAt, shopLocation: shopLocation, dealStatus: dealStatus, startingDate: startingDate)
}
}
let json = """
{
"keyword": "Some keyword",
"booking_type": "A type",
"expiry_date": 123456,
"created_at": null,
"shop_location": null,
"deal_status": "Declined",
"starting_date": 789456
}
""".data(using: .utf8)!
do {
let deal = try JSONDecoder().decode(ActiveDeals.self, from: json)
print(deal)
print(deal.dealStatus)
} catch {
print("error info: \(error)")
}
在这种情况下,输出仍然相同:
ActiveDeals(keyword: "Some keyword", bookingType: "A type", expiryDate: 123456, createdAt: nil, shopLocation: nil, dealStatus: __lldb_expr_67.DealStatus.DECLINED, startingDate: Optional(789456))
DECLINED