์ด๋ฒ ์๊ฐ์๋ key ์ด๋ฆ์ ์ปค์คํ ํ ๋ ์ฌ์ฉํ ์ ์๋ Coding Key ์ ์ง์ ์ธ์ฝ๋ฉ๊ณผ ๋์ฝ๋ฉ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
๊ทธ์ ์ ์? ์ปค์คํ
ํ ์ผ์ด ์๊ธธ๊น์?
api ์๋ต ๋ฐ์ดํฐ๊ฐ Camel Case ๊ฐ ์๋๋ผ snake case ๋ผ๋๊ฐ ๋ค๋ฅธ ํ์์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ swift ์ ์ปจ๋ฒค์
์ ๋ง์ง ์๋๋ฐ ์๋ฌํ ๊ฒฝ์ฐ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ค์ํ๋ฒ ์์ธํ ์ค๋ช
ํ๋ฉด!
์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ดํฐ ํต์ ์ ์ํ ๋ชจ๋ธ์ ๋ง๋ค๋, Codable Protocol ์ ์ฑํํ๋๋ฐ์
์ด๋, ๊ตฌํํ๋ ค๋ ๊ตฌ์กฐ์ฒด ์์ฑ๊ณผ JSON Data ์ key๊ฐ์ด ์ผ์นํด์ผ ์ ์์ ์ผ๋ก Decoding ํ ์ ์์ต๋๋ค
๊ทผ๋ฐ ๊ทธ๊ฒ ์ฝ์ง ์์ฃ ..? ๊ทธ๋ CodingKeys ๋ฅผ ์ฌ์ฉํด์ฃผ๋ฉด ๋ฉ๋๋ค.
์ ํ ๊ณต์๋ฌธ์์์๋ ์ธ์ฝ๋ฉ/๋์ฝ๋ฉ์ ์ํ ํค๋ก ์ฌ์ฉํ ์ ์๋ ํ์ ์ด๋ผ๊ณ ์ ์๊ฐ ๋์ด์์ต๋๋ค.
๊ทธ๋ผ ์ฌ์ฉ๋ฒ์ ์์๋ด ์๋ค.
openweathermap api์ ๊ฒฐ๊ณผ ์ผ๋ถ์
๋๋ค! ๋ฑ๋ด๋ Swift ์์ ์ฌ์ฉํ๊ธฐ ๊ทธ๋ ์ฃ ?
์ด๋ฌํ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ณ ์ํฉ๋๋ค.
struct Temp: Codable {
let temp: Double
let feelsLike: Double
let minTemp: Double
let maxTemp: Double
}
๊ทธ๋ผ ์๋์ ๋จ๊ณ๋ฅผ ๊ฑฐ์น๋ฉด ๋ฉ๋๋ค.
1. mapping ๋ ์์ฑ์ CodingKeys ์ด๊ฑฐํ์ ์ถ๊ฐํ๋ค
2. CodingKeys ์ด๊ฑฐํ์ CodingKey ํ๋กํ ์ฝ์ ์ฑํํ๋ค.
3. mapping ์ด ๋ฌ๋ผ์ง๋ ์์ฑ์ rawValue ๋ก ํ์ํ JSON Data์ ํค ๊ฐ์ ์
๋ ฅํฉ๋๋ค.
struct Temp: Codable {
let temp: Double
let feelsLike: Double
let minTemp: Double
let maxTemp: Double
enum CodingKeys: String, CodingKey {
case temp
case feelsLike = "feels_like"
case minTemp = "temp_min"
case maxTemp = "temp_max"
}
}
์ด๋๋์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํ์ต๋๋ค
๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ ์ธ์ฝ๋ฉ ๋ฐ ๋์ฝ๋ฉ ๊ณผ์ ์ ์ง์ ๊ตฌํํ์ฌ ์์ ๋ง์ ์ธ์ฝ๋ฉ ๋ฐ ๋์ฝ๋ฉ ๋ก์ง์ ์์ฑํ ์ ์์ต๋๋ค.
struct Member: Codable {
var name: String
var age: Int
var job: String?
func encode(to encoder: Encoder) throws {
var container = encoder.contatiner(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
guard (20...30).contains(age) else { throw EncodingError.invalidRange }
try container.encode(age, forKey: .age)
try container.encodeIfPresent(job, forKey: .job)
}
}
struct Member: Codable {
var name: String
var age: Int
var job: String?
init(from decoder: Decoder) throws {
let container = decoder.contatiner(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
age = try container.decode(Int.self, forKey: .age)
guard (20...30).contains(age) else { throw EncodingError.invalidRange }
job = try container.decodeIfPresent(String.self, forKey: .job)
}
}
์ธ์ฝ๋ฉ๊ณผ ๋์ฝ๋ฉ์ customizing ํ ๋ ์ฌ์ฉํ๋ ์ปจํ
์ด๋ ํ์
์ ๋ํ ์์ธํ ๋ด์ฉ์
KeyedEncodingContainerProtocol ๋ฐ UnkeyedEncoding Container ๋ฅผ ์ฐธ๊ณ
https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
https://inuplace.tistory.com/1224?category=1058164
https://tech.burt.pe.kr/swift/codable/encoding-decoding-custom-type
๊ธ ์ ์ฝ์์ต๋๋คใ ใ
contatiner -> container ๋ก ์คํ ์์ ํ๋ฉด ์ข์ ๊ฑฐ ๊ฐ์ต๋๋ค!