다음과 같이 struct를 정의하고,
struct Room: Decodable {
let hotelID: Int
let title: String
let price: Double
let wishlist: Bool
let longitude: Double
let latitude: Double
let rate: Int
let options: [String]
let img: String
}
json data를 모델 객체로 decoding 할 때 해당하는 key가 없는 경우,
init(from decoder: Decoder)
을 직접 구현해서 처리할 수 있다.
// 다음과 같이 데이터가 내려올 경우
[
{
"hotelId": 1,
"title": "title",
"price": 100,
"wishlist": false,
}
]
init(from decoder: Decoder) throws {
// 구현부를 작성.
}
CodingKeys를 정의하고, decodeIfPresent를 이용해 key가 없을 경우에 기본 값을 정의한다.
enum CodingKeys: String, CodingKey {
case hotelID = "hotelId"
case title, price, wishlist, longitude, latitude, rate, options, img
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
hotelID = try container.decode(Int.self, forKey: .hotelID)
title = try container.decode(String.self, forKey: .title)
price = try container.decode(Double.self, forKey: .price)
wishlist = try container.decode(Bool.self, forKey: .wishlist)
longitude = try container.decodeIfPresent(Double.self, forKey: .longitude) ?? 0
latitude = try container.decodeIfPresent(Double.self, forKey: .longitude) ?? 0
rate = try container.decodeIfPresent(Int.self, forKey: .longitude) ?? 0
options = try container.decodeIfPresent([String].self, forKey: .options) ?? []
img = try container.decodeIfPresent(String.self, forKey: .options) ?? ""
}
decodeIfPresent 대신 decode를 사용할 수도 있다.
longitude = (try? container.decode(Double.self, forKey: .longitude)) ?? 0
decodeIfPresent는 optional, decode은 non-optional 타입을 리턴한다.
decodeIfPresent
Return Value: A decoded value of the requested type, or nil if the Decoder does not have an entry associated with the given key, or if the value is a null value.
정리🙃.
model(struct, class)의 속성을 optional로 정의하고 싶지 않으면서,
decoding 시 keyNotFound error를 핸들링하기 위해
init(decoder:) 구현부를 직접 작성할 수 있다.
ref.
https://jinnify.tistory.com/71
https://zeddios.tistory.com/577