According to Federico Zanetello on his post Swift 4 Decodable: Beyond The Basics, Codable and Decobable protocols will works fine if you need to parse a subset of primitives (strings, numbers, bools, etc).
On your case, just making DealStatus conform to Decodable (as suggested by
JeremyP) should solve your problem. You can check on Playgrounds creating your own JSON data and trying to parse it:
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)")
}
And the output will be:
ActiveDeals(keyword: "Some keyword", bookingType: "A type", expiryDate: 123456, createdAt: nil, shopLocation: nil, dealStatus: __lldb_expr_61.DealStatus.DECLINED, startingDate: Optional(789456))
DECLINED
However, to become a better programmer you should always be curious and try to learn how things, so if you are interested on how you could conform to Decodable protocol (let's say you need custom keys, custom errors or some more complex data structure), this is how you can do it:
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)")
}
In this case the output is still the same:
ActiveDeals(keyword: "Some keyword", bookingType: "A type", expiryDate: 123456, createdAt: nil, shopLocation: nil, dealStatus: __lldb_expr_67.DealStatus.DECLINED, startingDate: Optional(789456))
DECLINED