我有这个枚举:
enum DealStatus:String {
case PENDING = "Pending"
case ACTIVE = "Active"
case STOP = "Stop"
case DECLINED = "Declined"
case PAUSED = "Paused"
}
和struct:
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?
}
在struct中我试图将枚举指定为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?
}
但是我收到了一些编译错误:
类型'ActiveDeals'不符合协议'可解码'
协议需要初始化程序'init(from :)',类型为'Decodable' (Swift.Decodable)
无法自动合成'可解码' 因为'DealStatus'不符合'Decodable'
答案 0 :(得分:6)
问题是只有当结构的所有属性都是Decodable
并且你的枚举不是Decodable
时,Swift才能自动合成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"
}
答案 1 :(得分:4)
错误表示类的某些属性不符合可解码协议。
为你的枚举添加可解码的一致性,它应该没问题。
extension DealStatus: Decodable { }
答案 2 :(得分:1)
根据Federico Zanetello的帖子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
然而,要成为一名更好的程序员,你应该总是好奇并尝试学习如何做事,所以如果你对如何符合可解码协议感兴趣(假设你需要自定义键,自定义错误或一些更复杂的数据)结构),你可以这样做:
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