์ง๋ ํธ์ ์ด์ด์ ์งํ!
์ด์ ์ง์ง ๋ง์ง๋ง ํํธ๋ค.
์ด์ ํธ์์๋ JSON
๋ฐ์ดํฐ์ ํด๋น ํค๊ฐ ์์ด๋ ์๋ฌ๊ฐ ๋์ง ์๊ณ ๊ธฐ๋ณธ๊ฐ์ ์ง์ ํ ์ ์๊ฒ ํ๋ค.
์ด๋, Generic
์ ์ด์ฉํ์์๋ค.
์ด๋ฒ ํธ์ ์์ฃผ ๊ฐ๋จํ๊ฒ ๋๋ผ ๊ฒ์ด๋ค.
๋ค๋ฅธ ํ์ ์ผ๋ก ํ๋ณํ ํ๋ ๊ฒ๊ณผ ๋ฆฌ์คํธ์ ๋ํ ์ฒ๋ฆฌ๋ค.
๋ค๋ฅธ ํ์ ์ผ๋ก ๋ฐ๊พธ๋๊ฑด ์ต์ ๋์ธ ํ์ ๊ณผ ์ต์ ๋์ด ์๋ ํ์ ์ ์ ์ฉํ ๊ฒ์ด๋ค.
์ต์ ๋์ด ์๋ ํ์
์ต์ ๋์ด ์๋๊ณ ๋ค๋ฅธ ํ์ ์บ์คํ ์ ๋ณด์
์ด์ ์ ํ๋
{
"isHidden" : "Y"
}
์ด ๊ฐ์ Bool
ํํ๋ก ๋ฐ๊ธฐ๋ฅผ ์งํ ํ ๊ฑด๋ฐ,
์ด๊ฒ๋ ๊ธฐ๋ณธ๊ฐ์ด true
๋๋ false
์ด๋ฏ๋ก
๋ค์ ๊ฒ๋ค๋ 2๊ฐ๊ฐ ๋์ฌ ๊ฒ์ด๋ค.
init(from decoder: Decoder){}
extension KeyedDecodingContainer{}
๊ทธ๋ฌ๋ฏ๋ก ๊ทธ๋ฅ protocol
๋ก ๋ฌถ์ด์ฃผ๊ณ
protocol JSONStringConverterAvailable {
static var defaultValue: Bool { get }
}
์ด์ ์ ๋ง๋ JSONDefaultWrapper
์์ Property Wrapper
๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ
enum JSONDefaultWrapper {
// ...
// Property Wrapper - Optional String To Bool
@propertyWrapper
struct StringConverterWrapper<T: JSONStringConverterAvailable> {
var wrappedValue: Bool = T.defaultValue
}
// ...
}
Decodable
๋ ์ ์ฉํด์ฃผ๊ณ
extension JSONDefaultWrapper.StringConverterWrapper: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.wrappedValue = (try container.decode(String.self)) == "Y"
}
}
KeyedDecodingContainer
ํ์ฅ๋ ํด์ฃผ๊ณ
extension KeyedDecodingContainer {
// ...
func decode<T: JSONStringConverterAvailable>(_ type: JSONDefaultWrapper.StringConverterWrapper<T>.Type, forKey key: Key) throws -> JSONDefaultWrapper.StringConverterWrapper<T> {
try decodeIfPresent(type, forKey: key) ?? .init()
}
}
์ด์ ํธ๋ค์ ๋ดค๋ค๋ฉด ์ดํดํ๊ธฐ ํจ์ฌ ์์ํ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ฐ๊ธฐ ์ํด ์ด์ ํธ์ JSONDefaultWrapper.TypeCase
์๋ ์ ์๋ฅผ ํด์ค๋ค.
๊ธฐ๋ณธ๊ฐ true
, false
๋๋ค!
enum TypeCase {
enum StringFalse: JSONStringConverterAvailable {
// ๊ธฐ๋ณธ๊ฐ - false
static var defaultValue: Bool { false }
}
enum StringTrue: JSONStringConverterAvailable {
// ๊ธฐ๋ณธ๊ฐ - false
static var defaultValue: Bool { true }
}
}
๊ทธ๋ฆฌ๊ณ ๋ง๋ฌด๋ฆฌ๋ก typealias
๋ฅผ ํตํด ๊ฐ์ถ๋ ค์ค๋ค.
enum JSONDefaultWrapper {
//...
typealias StringFalse = StringConverterWrapper<JSONDefaultWrapper.TypeCase.StringFalse>
typealias StringTrue = StringConverterWrapper<JSONDefaultWrapper.TypeCase.StringTrue>
}
๊ทธ๋ผ ์ธ ์ค๋น๋ ๋๋ฌ๋ค.
๊ทธ๋ฅ property wrapper 2๊ฐ ๋ง๋๋๊ฒ ๋์๋ ค๋?
์ฐ๋ ๋ฐฉ๋ฒ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ด์ ๊ณผ ๊ฐ๋ค.
class Posting: Decodable {
@JSONDefaultWrapper.StringFalse var stringFalseValue: Bool
@JSONDefaultWrapper.StringTrue var stringTrueValue: Bool
}
์ด๋ ๊ฒ ํด์ฃผ๋ฉด ์์ฃผ ์ ๋๋ค.
์ต์ ๋ ํ์
์ด๋ฒ์๋ ์กฐ๊ธ ๋ค๋ฅธ๊ฑธ ํด๋ณด์,
nil
๋ก ๋
๋๋๊ฒ ๋์ ์ผ์ด์ค๊ฐ ์์ ์ ์๋ค.
์๋ฅผ ๋ค์ด timestamp
๋ฅผ Date
๋ก ๋ฐ๊พผ๋ค๊ฑฐ๋..?
์ด ๊ฒฝ์ฐ์๋ ๊ธฐ๋ณธ ๊ฐ์ผ๋ก ์ค๋ ๋ ์ง๋ฅผ ๋ฃ๋๋ค๊ฑฐ๋ ์ด๋ฐ๊ฑด ๋ณ๋ก๋ค
์ฐจ๋ผ๋ฆฌ nil
๋ก์จ ๋
๋๋๊ฒ ๋ซ๋ค๊ณ ๋ณธ๋ค.
๊ทธ๋์ ์ ์ฉ์ ํด๋ณด์.
๋ ๋จ์ ์ธ ์ผ์ด์ค๋
protocol
์ ์ ์ฉํ์ง ์๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก enum JSONDefaultWrapper {}
์์ ์ ์ธ์ ํด์ค๋ค.
enum `JSONDefaultWrapper` {
// Property Wrapper - Optional Timestamp to Optinoal Date
@propertyWrapper
struct TimestampToOptionalDate {
var wrappedValue: Date?
}
}
์ฌ๊ธฐ์ ๋ด์ผํ ์ ์ wrappedValue๊ฐ ์ต์ ๋์ด๋ผ๋ ์ ?
๊ทธ๋ ๋ด ์ด๊ธฐํํด๋ ๋ฌธ์ ๊ฐ ์๋ค.
์ด์ฐจํผ nil
๋ก ๋ค์ด๊ฐ๋ฉด ๋๋๊น.
(์ฌ๊ธฐ์ struct
์์ฑ๊ณผ ๋์์ Decodable
์ ๋ฃ๊ณ init(from decoder: Decoder)
์ ๋ง๋ค๋ฉด ์๋์ผ๋ก init()
์ ์์ฑ ๋์ง ์๋ ๊ฒ์ ์๊ฒ ๋์๋ค.)
๊ทธ ๋ค์์ ๋ง์ฐฌ๊ฐ์ง๋ก
Decoadable
๋ฐ์์ฃผ๊ณ
extension JSONDefaultWrapper.TimestampToOptionalDate: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let timestamp = try container.decode(Double.self)
let date = Date.init(timeIntervalSince1970: timestamp)
self.wrappedValue = date
}
}
KeyedDecodingContainer
ํ์ฅํด์ฃผ๊ณ
func decode(_ type: JSONDefaultWrapper.TimestampToOptionalDate.Type, forKey key: Key) throws -> JSONDefaultWrapper.TimestampToOptionalDate {
try decodeIfPresent(type, forKey: key) ?? .init()
}
์ด๋ฌ๋ฉด ์ค๋น๋.
๋ฆฌ์คํธ
์ง์ง ์ง์ง ๋ง๋ฌด๋ฆฌ๋ก ๋ฆฌ์คํธ ์ฒ๋ฆฌ ๋์ง๊ณ ๋๋ด๊ธฐ
๋ณ๋๋ก ๋ฉํผ ๋ง๋ค ํ์ ์๋ค. ์ด๋ฏธ ๋ค ๊ฐ์ถฐ ์ก๋ค.
JSONDefaultWrapperAvailable.TypeCase
์ ์ ์๋ง ํด์ฃผ๊ณ !
enum TypeCase {
enum List<T: Decodable & ExpressibleByArrayLiteral>: JSONDefaultWrapperAvailable {
// ๊ธฐ๋ณธ๊ฐ - []
static var defaultValue: T { [] }
}
}
typealias
๋ง ์กฐ๋ ์ด๋ ต๊ฒ ์๋ด์ฃผ๋ฉด
enum JSONDefaultWrapper {
typealias EmptyList<T: Decodable & ExpressibleByArrayLiteral> = Wrapper<JSONDefaultWrapper.TypeCase.List<T>>
}
์ฌ์ฉ ์ค๋น ๋!!
๊ฒฐ๊ณผ
ํค ๋ฏธ์กด์ฌ
ํค ์กด์ฌ
์์ฃผ ์ข์ใ ใ ใ ๋๋์ด ๋!