struct MapAddress: Decodable {
let address: Address?
let addressName: String
let addressType: String?
let roadAddress: String?
let x: String
let y: String
enum CodingKeys: String, CodingKey {
case address, x, y
case addressName = "address_name"
case addressType = "address_type"
case roadAddress = "road_address"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.address = try? values.decode(Address.self, forKey: .address)
self.addressName = (try? values.decode(String.self, forKey: .addressName)) ?? ""
self.addressType = try? values.decode(String.self, forKey: .addressType)
self.roadAddress = try? values.decode(String.self, forKey: .roadAddress)
self.x = (try? values.decode(String.self, forKey: .x)) ?? ""
self.y = (try? values.decode(String.self, forKey: .y)) ?? ""
}
}
사실 이 부분에 대해서 이전에는 KeyNotFound에러가 발생할 수 있기때문에 모든 멤버들을 옵셔널로 선언한 이후에 decode하였다
-> 하지만 이 같은 경우는 모든 데이터에 대해 옵셔널바인딩을 해줘야하는 단점이 존재한다
내가 개발하는데 있어서 사용하고자하는 데이터와 그렇지않은 데이터를 기준으로 옵셔널을 선언하는 기준으로 잡는게 어떨까 생각해보았다
사용하려는 데이터는 그대로, 사용하지않는 데이터를 옵셔널을 붙여주어서 사용하지않은 데이터가 내려오지않아 nil값이여도 상관이 없고 사용하고자하는 데이터는 그대로 받아오기때문에 사용할때 옵셔널 바인딩을 거치지않아도 된다는 장점이 있다
우리가 사용하려는 API들은 항상 정해져있는 틀이 존재하고 우리는 이에 맞춰서 Decodable하기위한 구조체를 정의한다
흔치 않은 일이지만 만약에 API의 데이터 구조가 변경된다면 기존에 정의되있는 틀에서는 Decodable시 찾지못하게되어 KeyNotFound에러가 발생할 수 있다
이와 같은 일이 있기에 init(decoder:) 생성자를 이용하여 디폴트값을 넣어준다면 우리는 API의 데이터구조에 어긋나더라도 저 생성자를 통해 디폴트값을 넣어 가지게되기에 런타임크래시가 날 위험이 감소하게된다