Slide 1

Slide 1 text

Property Wrapperͽ Decodable΄ϔϢζϸϕ㮔Ψ戔ਧ 櫏΀JSONϹφϪЀφ΁揗ͧ΀͚

Slide 2

Slide 2 text

Jierong Liҁ๫҂ • ໌ୗտᐒΜΗΕ • iOSεЀυϘί • h&ps:/ /jierong.dev • ڡΗͼ晁㻑΁ιϐϑϷ݇ے

Slide 3

Slide 3 text

Ξͥ͘ΡDecodable enum Bar: String, Decodable { case case1, case2 } struct Foo: Decodable { let array: [Int] let string: String let int: Int let double: Double let bar: Bar }

Slide 4

Slide 4 text

ϔϢζϸϕ㮔戔ਧ enum Bar: String, Decodable { case case1, case2 } struct Foo: Decodable { let array: [Int] let string: String let int: Int let double: Double let bar: Bar private enum CodingKeys: CodingKey { case array, string, int, double, bar } init(from decoder: Decoder) throws { let container = decoder.container(keyedBy: CodingKeys.self) array = decoder.decodeIfPresent([Int].self, forKey: .array) ?? [] string = decoder.decodeIfPresent(String.self, forKey: .string) ?? "" int = decoder.decodeIfPresent(Int.self, forKey: .int) ?? 0 double = decoder.decodeIfPresent(Double.self, forKey: .double) ?? -1 bar = decoder.decodeIfPresent(Bar.self, forKey: .bar) ?? .case2 } }

Slide 5

Slide 5 text

᭗ଉ΀αϘτϰ϶ασЄ enum Bar: String, Decodable { case case1, case2 } struct Foo: Decodable { let array: [Int] let string: String let int: Int let double: Double let bar: Bar private enum CodingKeys: CodingKey { case array, string, int, double, bar } init(from decoder: Decoder) throws { let container = decoder.container(keyedBy: CodingKeys.self) array = decoder.decodeIfPresent([Int].self, forKey: .array) ?? [] string = decoder.decodeIfPresent(String.self, forKey: .string) ?? "" int = decoder.decodeIfPresent(Int.self, forKey: .int) ?? 0 double = decoder.decodeIfPresent(Double.self, forKey: .double) ?? -1 bar = decoder.decodeIfPresent(Bar.self, forKey: .bar) ?? .case2 } init(array: [Int] = [], string: String = "", int: Int = 0, double: Double = -1, bar: Bar = .case2) { self.array = array self.string = string self.int = int self.double = double self.bar = bar } }

Slide 6

Slide 6 text

ϔϢζϸϕ㮔͢ӞͺͶͧͽΘ enum Bar: String, Decodable { case case1, case2 } struct Foo: Decodable { let array: [Int] let string: String let int: Int let double: Double let bar: Bar private enum CodingKeys: CodingKey { case array, string, int, double, bar } init(from decoder: Decoder) throws { let container = decoder.container(keyedBy: CodingKeys.self) array = decoder.decodeIfPresent([Int].self, forKey: .array) ?? [] string = decoder.decode(String.self, forKey: .string) int = decoder.decode(Int.self, forKey: .int) double = decoder.decode(Double.self, forKey: .double) bar = decoder.decode(Bar.self, forKey: .bar) } init(array: [Int] = [], string: String, int: Int, double: Double, bar: Bar) { self.array = array self.string = string self.int = int self.double = double self.bar = bar } }

Slide 7

Slide 7 text

晄౮ͭ͵͚ͩ; • Property WrapperͽϔϢζϸϕ㮔΄戔ਧ • ݶͮόαϤ΁䌏ͭͼ晅͜ϔϢζϸϕ㮔΄戔ਧ • όαϤࢴํ΀ϔϢζϸϕ㮔΄戔ਧ

Slide 8

Slide 8 text

ݶͮόαϤ΁䌏ͭͼ晅͜ϔϢζϸϕ㮔΄戔ਧ struct Foo: Decodable { @DefaultBy([]) var array: [Int] } Decodable΄ᇙ௔΁Ξ͹ͼ !

Slide 9

Slide 9 text

υδϚϷμφͽ䌏㳌 protocol Default { associatedtype Value static var defaultValue: Value { get } } @propertyWrapper struct DefaultDecodable: Decodable where D.Value: Decodable { let wrappedValue: D.Value init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() wrappedValue = try container.decode(D.Value.self) } init() { wrappedValue = D.defaultValue } }

Slide 10

Slide 10 text

ExtensionͽηЄϝЄϺЄϖ extension KeyedDecodingContainer { func decode(_ type: DefaultDecodable.Type, forKey key: Key) throws -> DefaultDecodable { try decodeIfPresent(type, forKey: key) ?? .init() } }

Slide 11

Slide 11 text

ᑮ protocol EmptyInitializable { init() } struct EmptyDefault: Default { static var defaultValue: Value { .init() } } extension Array: EmptyInitializable {} extension String: EmptyInitializable {} struct Foo: Decodable { @DefaultDecodable var array: [Int] @DefaultDecodable var string: String ... }

Slide 12

Slide 12 text

ෆቘ enum CommonDefault { struct Empty: Default { static var defaultValue: Value { .init() } } } enum DefaultBy { typealias Empty = DefaultDecodable> } struct Foo: Decodable { @DefaultBy.Empty var array: [Int] @DefaultBy.Empty var string: String ... }

Slide 13

Slide 13 text

හ㮔 enum CommonDefault { ... struct ZeroInt: Default { static var defaultValue: Int {̴.zero̴} } struct OneInt: Default { static var defaultValue: Int { 1 } } struct MinusOneInt: Default { static var defaultValue: Int { -1 } } struct ZeroDouble: Default { static var defaultValue: Double {̴.zero̴} } struct OneDouble: Default { static var defaultValue: Double { 1 } } struct MinusOneDouble: Default { static var defaultValue: Double { -1 } } ... }

Slide 14

Slide 14 text

හ㮔 enum CommonDefault { ... struct Zero: Default { static var defaultValue: Value {̴.zero̴} } struct One: Default { static var defaultValue: Value { 1 } } struct MinusOne: Default { static var defaultValue: Value { -1 } } } enum DefaultBy { ... typealias Zero = DefaultDecodable> typealias One = DefaultDecodable> typealias MinusOne = DefaultDecodable> } struct Foo: Decodable { ... @DefaultBy.Zero var int: Int @DefaultBy.MinusOne var double: Double ... }

Slide 15

Slide 15 text

όαϤࢴํ protocol SelfDefault: Default { static var defaultValue: Self { get } } extension Bar: SelfDefault { var defaultValue: Bar { .case2 } } enum DefaultBy { ... typealias `Self` = DefaultDecodable } ςϣμ϶φͽΘSelf΄ګ夹͢伋͵ͱΡ͵Η̵ࣳവ抷͢ӧݢᚆ

Slide 16

Slide 16 text

όαϤࢴํ protocol SelfDefault { static var defaultValue: Self { get } } enum CommonDefault { ... struct `Self`: Default { static var defaultValue: Value { Value.defaultValue } } } enum DefaultBy { ... typealias `Self` = DefaultDecodable> } struct Foo: Decodable { ... @DefaultBy.Self var bar: Bar }

Slide 17

Slide 17 text

๋奰奾ຎ struct Foo: Decodable { @DefaultBy.Empty var array: [Int] @DefaultBy.Empty var string: String @DefaultBy.Zero var int: Int @DefaultBy.MinusOne var double: Double @DefaultBy.Self var bar: Bar } φϐκϷͭ͵̵ͭ᭗ଉ΀αϘτϰ϶ασЄΘκЄϤ h"ps:/ /github.com/myihsan/DefaultDecodableWrapper

Slide 18

Slide 18 text

ΚΟͭ͡͵ͩ; extension DefaultDecodable: Equatable where D.Value: Equatable {} extension DefaultDecodable: Encodable where D.Value: Encodable {}

Slide 19

Slide 19 text

ΚΟͭ͡͵ͩ; extension DefaultDecodable: Equatable where D.Value: Equatable {} // extension DefaultDecodable: Encodable where D.Value: Encodable {}̴ // { "wrappedValue": 1 } extension DefaultDecodable: Encodable where D.Value: Encodable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(wrappedValue) } } ϓφϕώЄϭ;ץྋͭ͵ϮЀϝЄ΁ఽ拽

Slide 20

Slide 20 text

ͪᶉ宛͘Π͢;͚ͪͬ͜Δͯ