Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Property WrapperでDecodableのデフォルト値を設定 / Providing Default Value for Decodable Property by Property Wrapper

8ab71237da39f6b1ec47da53f33c3ec8?s=47 Jierong Li
February 26, 2021
77

Property WrapperでDecodableのデフォルト値を設定 / Providing Default Value for Decodable Property by Property Wrapper

8ab71237da39f6b1ec47da53f33c3ec8?s=128

Jierong Li

February 26, 2021
Tweet

Transcript

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

  2. Jierong Liҁ๫҂ • ໌ୗտᐒΜΗΕ • iOSεЀυϘί • h&ps:/ /jierong.dev •

    ڡΗͼ晁㻑΁ιϐϑϷ݇ے
  3. Ξͥ͘Ρ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 }
  4. ϔϢζϸϕ㮔戔ਧ 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 } }
  5. ᭗ଉ΀αϘτϰ϶ασЄ 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 } }
  6. ϔϢζϸϕ㮔͢ӞͺͶͧͽΘ 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 } }
  7. 晄౮ͭ͵͚ͩ; • Property WrapperͽϔϢζϸϕ㮔΄戔ਧ • ݶͮόαϤ΁䌏ͭͼ晅͜ϔϢζϸϕ㮔΄戔ਧ • όαϤࢴํ΀ϔϢζϸϕ㮔΄戔ਧ

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

    Decodable΄ᇙ௔΁Ξ͹ͼ !
  9. υδϚϷμφͽ䌏㳌 protocol Default { associatedtype Value static var defaultValue: Value

    { get } } @propertyWrapper struct DefaultDecodable<D: Default>: 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 } }
  10. ExtensionͽηЄϝЄϺЄϖ extension KeyedDecodingContainer { func decode<D>(_ type: DefaultDecodable<D>.Type, forKey key:

    Key) throws -> DefaultDecodable<D> { try decodeIfPresent(type, forKey: key) ?? .init() } }
  11. ᑮ protocol EmptyInitializable { init() } struct EmptyDefault<Value: EmptyInitializable>: Default

    { static var defaultValue: Value { .init() } } extension Array: EmptyInitializable {} extension String: EmptyInitializable {} struct Foo: Decodable { @DefaultDecodable<EmptyDefault> var array: [Int] @DefaultDecodable<EmptyDefault> var string: String ... }
  12. ෆቘ enum CommonDefault { struct Empty<Value: EmptyInitializable>: Default { static

    var defaultValue: Value { .init() } } } enum DefaultBy { typealias Empty<Value: Decodable & EmptyInitializable> = DefaultDecodable<CommonDefault.Empty<Value>> } struct Foo: Decodable { @DefaultBy.Empty var array: [Int] @DefaultBy.Empty var string: String ... }
  13. හ㮔 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 } } ... }
  14. හ㮔 enum CommonDefault { ... struct Zero<Value: Numeric>: Default {

    static var defaultValue: Value {̴.zero̴} } struct One<Value: Numeric>: Default { static var defaultValue: Value { 1 } } struct MinusOne<Value: Numeric>: Default { static var defaultValue: Value { -1 } } } enum DefaultBy { ... typealias Zero<Value: Decodable & Numeric> = DefaultDecodable<CommonDefault.Zero<Value>> typealias One<Value: Decodable & Numeric> = DefaultDecodable<CommonDefault.One<Value>> typealias MinusOne<Value: Decodable & Numeric> = DefaultDecodable<CommonDefault.MinusOne<Value>> } struct Foo: Decodable { ... @DefaultBy.Zero var int: Int @DefaultBy.MinusOne var double: Double ... }
  15. όαϤࢴํ protocol SelfDefault: Default { static var defaultValue: Self {

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

    } } enum CommonDefault { ... struct `Self`<Value: SelfDefault>: Default { static var defaultValue: Value { Value.defaultValue } } } enum DefaultBy { ... typealias `Self`<Value: Decodable & SelfDefault> = DefaultDecodable<CommonDefault.Self<Value>> } struct Foo: Decodable { ... @DefaultBy.Self var bar: Bar }
  17. ๋奰奾ຎ 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
  18. ΚΟͭ͡͵ͩ; extension DefaultDecodable: Equatable where D.Value: Equatable {} extension DefaultDecodable:

    Encodable where D.Value: Encodable {}
  19. ΚΟͭ͡͵ͩ; 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) } } ϓφϕώЄϭ;ץྋͭ͵ϮЀϝЄ΁ఽ拽
  20. ͪᶉ宛͘Π͢;͚ͪͬ͜Δͯ