์ง๋ ํธ์ ์ด์ด์ ์งํ!
์ง๋ํธ ๋ง์ง๋ง์ ๋จ์ ์ ์ ์ด์ฃผ๋ฉฐ ๋ง๋ฌด๋ฆฌ๋ฅผ ์ง์์๋ค.
์ด๋ฒํธ์ ๊ทธ ๋จ์ ์ ๋ณด์ํ๊ธฐ ์ํ ํธ.
๋ฐฐ์ฐ๋ ๋์ด๋๊ฐ ์๊ฐ๋ณด๋ค ๋์๋ค.
์ง๋ํธ์ ์ ์ ๋จ์ ์ ์ผ๋ถ๋ถ์ด๋ค
โฆ ํ์ง๋ง,
isHidden
์ด๋ผ๋ ๊ฐ์ด ์์ ๊ฒฝ์ฐ, ๋ชจ๋ธ์ ํด๋น ๊ฐ์ ์ต์ ๋์ฒ๋ฆฌ ํด์ฃผ๋๋ผ๋ ์ด ์ฝ๋๋throw
ํ๊ฒ ๋๋ค. โฆ ์ค์ ๋ก ์๋ฒ์์๋Request
์ ๋ฐ๋ผResponse
๊ฐ ๋ฌ๋ผ์ง ๊ฐ๋ฅ์ฑ์ ์กด์ฌํ๋ค. ๊ทธ๋ ๊ธฐ์ ์ด ๋จ์ ์ ์น๋ช ์ ์ด๋ผ ์๊ฐ๋๋ค.
์ฐจ๊ทผ ์ฐจ๊ทผ ํ๋์ฉ ํ์ด๋๊ฐ๋ณด์
์ฐ์ ์ String
์ ๋ํด์๋ง ๋ณด๊ณ Generic
์ ์ด์ฉํด ๋ฒ์๋ฅผ ๋ํ ๋ณด์.
๊ทธ๋ฆฌ๊ณ ์ด์ ๊ณผ ๊ฐ์ด ๋ค๋ฅธ ํ์ ์ผ๋ก ์บ์คํ ํ๋ ๋ฐฉ๋ฒ๋ ์์๋ณผ ์์ ์ด๋ค.
Codable ํํธ๋ง 3ํธ์ผ๋ก ๋๋ ์ผ ํ ๋ฏ ํ๋ค.
์ด๊ฒ๊น์ง ํ๊ณ ๋์์ผ ๋น๋ก์ ์ค๋ฌด์ ์จ๋ ๋๊ฒ ๋ค๋ ํ์ ์ด ๋ค์๋ค.
์ฒซ๋ฒ์งธ JSON ํํ๋ ๋ค์๊ณผ ๊ฐ๋ค
{
"usrNm" : "KJS"
}
๊ทธ๋ฆฌ๊ณ Class
ํํ๋ ๋ค์๊ณผ ๊ฐ๋ค
class UserClass: Decodable {
var usrNm: String
var usrAddress: String
}
์ฌ๊ธฐ์ ์ฃผ๋ชฉํด์ผํ ์ ์ ํด๋์ค
์๋ usrAddress
๋ ์กด์ฌํ์ง๋ง JSON
์์ ์กด์ฌํ์ง ์๋๋ค๋์ ์ด๋ค.
๋ค์ ๋งํด, JSON์ ์์ ๊ฒฝ์ฐ ๊ธฐ๋ณธ๊ฐ ์ฒ๋ฆฌ๋ฅผ ํ๊ณ ์ถ๋ค๋ ๊ฒ์ด๋ค.
Wrapper ์์ฑ
@propertyWrapper
struct JsonStringWrapper: Decodable {
let wrappedValue: String
}
๋ฉํผ๊ฐ Decodable
ํ๋กํ ์ฝ์ ๋ฐ๊ณ ์๋ค. ๊ทธ๋ฆฌ๊ณ init decode
๋ ๋, ์ ์๊ฐ ํ์ํ๋ค.
extension JsonStringWrapper {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.wrappedValue = try container.decode(String.self)
}
}
์ฌ๊ธฐ๊น์ง ์ด์ ํธ๊น์ง ๊ฐ๋ค.
๋ฌธ์ ๋ ์๋ ๊ธฐ๋ณธ ๊ฐ์ ๋ํด ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค.
์ฐ์ ์์ ๋ฉํผ์ init()
์ ์ถ๊ฐํด์ฃผ์
@propertyWrapper
struct JsonStringWrapper: Decodable {
let wrappedValue: String
init() {
wrappedValue = ""
}
}
๊ทธ๋ผ ๋จ์ ์ด๊ธฐํ์ ๋น๊ฐ์ ๊ฐ์ง๊ฒ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค์์ด ํต์ฌ์ด๋ค.
extension KeyedDecodingContainer {
func decode(_ type: JsonStringWrapper.Type, forKey key: Key) throws -> JsonStringWrapper {
try decodeIfPresent(type, forKey: key) ?? .init()
}
}
key
๊ฐ ์กด์ฌํ๋ฉด extension JsonStringWrapper
๋ถ๋ถ์ decode
๋ฅผ ํ๊ฒ๋๊ณ
ํด๋น ํค๊ฐ ์๋ค๋ฉด decodeIfPresent
๋ nil์ ๋ฑ๊ธฐ ๋๋ฌธ์ .init()
์ด ๋๋ค.
์ด๊ฑธ ๋จผ์ ํ์ด์ผํ๋๋ฐ, ์ ํธ ๋์ด๋๊ฐ ๋ ๋์๋๊ฑฐ ๊ฐ๋ค? ์๋๊ฐ ๋ชจ๋ฅด๊ฒ ๋ค. ์ extension KeyedDecodingContainer์ ๋๋ ๋๋ฌด ์์ํด์ ์ด๊ฒ ๋ ์ด๋ ค์ด๊ฑฐ ๊ฐ๊ธฐ๋ํ๊ณ โฆ
์์ ๋ง์ ๊ฑฐ์ ๊ฐ์ง๋ง ์กฐ๊ธ ๋ค๋ฅด๊ฒ ํด๋ณด์๋ฉด
key
๋ ์ ์์ JSON
๊ฐ ์์ usrNm
์ด๋ผ๋ ๊ฒ์ ์๋ฏธํ๊ณ ,
์ด๊ฒ ์กด์ฌํ๋ฉด ๊ธฐ์กด init(from decoder:)
๋ฅผ ํ์์ ์ด๊ธฐํ๋ฅผ ์ํค๋ ๊ฒ์ด๊ณ
์กด์ฌํ์ง ์์ผ๋ฉด ๋ฏธ๋ฆฌ ์ ์ํ init()
์ ํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
๊ฑฐ์ ๊ฐ์ ๋ง์ด์ง๋ง ๋ฐ๋ณต์ ์ค์ํ๋๊น..!
๊ฒฐ๋ก ์ ์ ๋ ๊ฒํ๋ฉด ์๋ฒ์์ JSON
์ ๊ฐ์ด ์๋ด๋ ค์๋ Decodable
์ ์ด์ฉํด ๋ฏธ๋ฆฌ ์ ํ ์ด๊ธฐ๊ฐ์ผ๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ค๋๊ฒ!
์ ์ด๊ฒ์ ํ๋์ง๊ฐ ์ค์ํ๋ค.
์ด๊ฒ์ ์์ํ ํ์คํ ๋ฆฌ๋ฅผ ์ ๋ฆฌํด๋ณด์๋ฉด ์๋์ ๊ฐ๋ค.
1.Codable
์ ์ด์ฉํ์ฌ
์๋ฒ์์ JSON
๊ฒฐ๊ณผ ๊ฐ์ ๊ฐ์ฒดํ ํ ์ ์๋ค
์์ฌ์ด์
JSON
๊ฒฐ๊ณผ์ ์ํ๋ ๊ฐ์ด ์์๋, 0
๊ณผ ๊ฐ์ ์ด๊ธฐ๊ฐ์ ์ฃผ๊ณ ์ถ๋ค๊ฑฐ๋ ์๋ฃํ์ ๋ณ๊ฒฝํ๊ณ ์ถ๋ค๋ฉด
init(from decoder: Decoder)
๋ถ๋ถ์ ๋ชจ๋ ํ๋กํผํฐ์ ๋ํด ๋ค ์ค์ ์ ํด์ค์ผ ํ๋ค.
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
// ๋ชจ๋ ํ๋กํผํฐ ์ ์ธํด์ฃผ๊ธฐ
self.propertyA = try container.decode(String.self)
self.propertyB = try container.decode(Bool.self)
self.propertyC = try container.decode(Int.self)
self.propertyD = try container.decode(String.self)
...
}
๋ฐ๋ผ๋์
ํ๋กํผํฐ ๊ฐฏ์ ๋งํผ init
ํํธ์ ์ญ ๋์ดํ๋ ๊ฒ์ ๊ฐ์ ์ ํ์์ฑ์ ๋๋
2. Property Wrapper
๋ฅผ ์ด์ฉํ๋ฉด
init(from decoder: Decoder)
๋ฅผ ์ํด๋ ๋๋ค.
์ฅ์
@propertyWrapper
struct StringBoolConverter {
let wrappedValue: Bool
}
extension StringBoolConverter: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let stringBool = try? container.decode(String.self)
wrappedValue = stringBool == "Y"
}
}
์์ ๊ฐ์ ๋ฉํผ๋ฅผ ๋ง๋ค์ด ๋๋ค๋ฉด
{
"isHidden" : "Y"
}
์์ ๊ฐ์ JSON
๊ฒฐ๊ณผ๋
struct Model: Codable {
@StringBoolConverter var isHidden: Bool
}
์์ ๊ฐ์ด ํด์ฃผ๋ฉด ๊น๋ํ๊ฒ init(from decoder:)
ํํธ ์์ด ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
์์ฌ์ด์
JSON
๊ฒฐ๊ณผ ๋ด์ isHidden
์ด๋ผ๋ ๊ฐ์ด ์๋ค๋ฉด init
์ throw
๋ฅผ ํ๊ฒ ๋์ด ๊ฐ์ฒด ์์ฑ์ด ๋์ง ์๋๋ค.
๋ฐ๋ผ๋์
ํ๋กํผํฐ๋ ๋ง๋ค์ด๋์ง๋ง JSON
๊ฒฐ๊ณผ ๋ด์ ํด๋น ํค๊ฐ ๋ด๋ ค์ค์ง ์์ ๊ฒฝ์ฐ ๋ฏธ๋ฆฌ ์ง์ ํ default
๊ฐ์ผ๋ก ์ด๊ธฐํ ๋๊ธธ ๋ฐ๋.
3. 2์ Property Wrapper
๊ฐ์
์์ ์ธ๋ฒ์ด๋ ๋งํ์ง๋ง ํ๋ฒ๋ ๋งํ์๋ฉด key
๊ฐ ์กด์ฌํ๋ฉด ๋ฏธ๋ฆฌ ์ ์ํ init
์ ํ์ฐ๊ฒ ํ๊ณ
ํค๊ฐ ์๋ค๋ฉด ๋ฏธ๋ฆฌ ์ ํ ์ด๊ธฐ๊ฐ์ผ๋ก ์ด๊ธฐํ๋๊ฒ ํ์
@propertyWrapper
struct JsonStringWrapper: Decodable {
let wrappedValue: String
init() {
wrappedValue = ""
}
}
extension KeyedDecodingContainer {
func decode(_ type: JsonStringWrapper.Type, forKey key: Key) throws -> JsonStringWrapper {
try decodeIfPresent(type, forKey: key) ?? .init()
}
}
์ฅ์
JSON
์ ์ ์ํ ํค๊ฐ ์์ด๋ init()
์ ์ ์ํ๋๋ก ๋ฉํผ๊ฐ์ ""
์ผ๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ค.
์์ฌ์ด์
๋ง์ง๋ง ์ฝ๋๋ง ๋ณด์
extension KeyedDecodingContainer {
func decode(_ type: JsonStringWrapper.Type, forKey key: Key) throws -> JsonStringWrapper {
try decodeIfPresent(type, forKey: key) ?? .init()
}
}
์ด๋ถ๋ถ์ type
์ ์ด๋ฒ์ ๋ง๋ JsonStringWrapper
์ ๋ํด์๋ง ๋ฐ์์ ํ๋ ๋ฉ์๋์ด๋ค.
๋ค์ ๋งํด,
JSON
๊ฒฐ๊ณผ ๊ฐ๋ค ์ฒ๋ฆฌ๋ฅผ ์ํด ๋ง์ฐฌ๊ฐ์ง๋ก Int
, Double
, Float
, Bool
๋ฑ์ ๋ฉํผ๋ก ๋ง๋ค๊ฒ ๋๋ค๋ฉด
ํด๋น ๋ฉ์๋๋ ๋์ผํ๊ฒ ์ฆ๊ฐ๋๊ฒ ๋๋ค.
๊ทธ๋ผ์ ๋ฐ๋ผ ์ด๊ฒ ๋ํ ์์ฝ๋ค๊ณ ๋๊ปด์ง๋ฉฐ ๊ฐ์ ์ ํ์์ฑ์ ๋๋ผ๊ฒ ๋์๋ค.
๊ทธ๋์ ์ด ์์ฌ์์ ๋ ๋ฌ๋๊ธฐ ์ํด ๋ค์ํธ์ Generic
์ ์ด์ฉํ์ฌ
ํด๋น ๋ถ๋ถ์ ์ค์ด๋ ๊ฒ์ ์ด์ ์ ๋ง์ถฐ ๊ธ์ ์จ๋ณด๊ณ ์ ํ๋ค.
๋.