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

しくみから理解するSwiftUI

266af7918931b0ea15eae9e8f42ecfa6?s=47 kumamotone
September 18, 2019

 しくみから理解するSwiftUI

2019/08/07 Bonfire iOS #6
https://yj-meetup.connpass.com/event/136285/

apple/swift-evolution:

SE-0255: Implicit return from single expressions
https://github.com/apple/swift-evolution/blob/master/proposals/0255-omit-return.md

SE-XXXX: Function Builders
https://github.com/apple/swift-evolution/blob/9992cf3c11c2d5e0ea20bee98657d93902d5b174/proposals/XXXX-function-builders.md

SE-0244: Opaque Result Type
https://github.com/apple/swift-evolution/blob/master/proposals/0244-opaque-result-types.md

SE-0258: Property Wrappers
https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md

See Also:

SwiftUIの魔法を実現する仕組み (Custom Attributes, Function Builder)
https://qiita.com/kentrino/items/dc6e77a0ddd21187cc55

SwiftUIのコードを読み解く
https://blog.personal-factory.com/2019/06/07/understand-swiftui-code/

Swift 5.1 に導入される Opaque Result Type とは何か
https://qiita.com/koher/items/338d2f2d0c4731e3508f

Opaque Result Typeの解説
https://qiita.com/omochimetaru/items/f13fe3e54fab01648ba4

SwiftUIで使用されているSwift5.1の新機能 - クックパッド開発者ブログ
https://techlife.cookpad.com/entry/2019/06/25/120000Qa

SwiftUIのProperty Wrappersとデータへのアクセス方法 - Qiita
https://qiita.com/shiz/items/6eaf87fa79499623306a

266af7918931b0ea15eae9e8f42ecfa6?s=128

kumamotone

September 18, 2019
Tweet

Transcript

  1. ͘͠Έ͔Βཧղ͢ΔSwiftUI 2019/09/18 iOSDC Reject Conference (Day. 2) twitter.com/kumamo_tone

  2. None
  3. • iOS/AndroidΤϯδχΞ • Yahoo!ΧϨϯμʔ iOS։ൃ • ษڧձӡӦ • Bonfire iOSɺWWDC

    Extended ͳͲ • potatotips #65 ΋ΑΖ͘͠ • ϚΠϒʔϜ • ఱؾͷࢠ ۽ຊ ࿨ਖ਼ (@kumamo_tone)
  4. • ୈҰ෦: some View ΍ VStack/HStack Λ࣮ݱ͢Δػೳ • Implicit return

    from single expressions • Function Builder • Opaque Result Type • ୈೋ෦: @State ΍ @Binding Λ࣮ݱ͢Δػೳ • Property Wrappers • ૝ఆର৅ऀ • ؾܰʹཧղ͍ͨ͠ • SwiftUI ؾʹͳͬͯ͸͍Δ͚Ͳ͋·ΓखΛ෇͚Ε͍ͯͳ͍ TL;DR
  5. None
  6. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } }
  7. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } public protocol View { associatedtype Body : View var body: Self.Body { get } } 7JFXϓϩτίϧͷ͜ͱ 7JFXϓϩτίϧͷఆٛ
  8. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } public protocol View { associatedtype Body : View var body: Self.Body { get } } 7JFXϓϩτίϧͷ͜ͱ 7JFXϓϩτίϧͷఆٛ ٙ໰
  9. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } TPNFͬͯԿʁ͆
  10. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } TPNFͬͯԿʁ͆ ͜ͷதͰ͸ Կ͕ߦΘΕ͍ͯΔʁ
  11. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } SFUVSOͲ͜ʹߦͬͨʁ ͜ͷதͰ͸ Կ͕ߦΘΕ͍ͯΔʁ TPNFͬͯԿʁ͆
  12. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } SFUVSOͲ͜ʹߦͬͨʁ ʁ TPNFͬͯԿʁ͆ ͜ͷதͰ͸ Կ͕ߦΘΕ͍ͯΔʁ
  13. " Magic?

  14. " No.

  15. Swift5.1ʹ௥Ճ͞Εͨɺ3ͭͷ৽ػೳʹΑͬͯઆ໌Ͱ͖Δ • Implicit return from single expressions • Function builders

    • Opaque Result Type some View Λ࣮ݱ͢Δػೳ
  16. Swift5.1ʹ௥Ճ͞Εͨɺ3ͭͷ৽ػೳʹΑͬͯઆ໌Ͱ͖Δ • Swift Evolution: SE-0255 • Implicit return from single

    expressions • Swift Evolution: SE-XXXX • Function builders • Swift Evolution: SE-0244 • Opaque Result Type some View Λ࣮ݱ͢Δػೳ ͻͱͭΊʂ
  17. Implicit return from single expressions

  18. SE-0255: Implicit return from single expressions • ϝϦοτ • ͖ͬ͢Γ͢Δ

    ΫϩʔδϟͰ͸લ͔Βɺ͕ࣜͻͱ͔ͭ͠ͳ͍ͱ͖returnΛলུͰ͖ͨ let names = persons.map { $0.name }
  19. SE-0255: Implicit return from single expressions struct Rectangle { var

    width = 0.0, height = 0.0 var area: Double { width * height } } ؔ਺΍ Computed Property Ͱ΋OK ΫϩʔδϟͰ͸લ͔Βɺ͕ࣜͻͱ͔ͭ͠ͳ͍ͱ͖returnΛলུͰ͖ͨ • ϝϦοτ • ͖ͬ͢Γ͢Δ let names = persons.map { $0.name }
  20. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } }
  21. struct ContentView: View { var body: some View { return

    VStack { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } SFUVSO͕লུ͞Ε͍ͯͨ
  22. • Swift Evolution: SE-0255 • Implicit return from single expressions

    • Swift Evolution: SE-XXXX • Function builders (draft proposal) • Swift Evolution: SE-0244 • Opaque Result Type some View Λ࣮ݱ͢Δػೳ ;ͨͭΊʂ
  23. Function builders (draft proposal)

  24. • վߦ۠੾Γͷཁૉ͔ͨͪΒɺม਺એݴͱؔ਺ݺͼग़͠Λੜ੒͢Δ • @_functionBuilderΛ͚ͭͨؔ਺͸ɺFunction builderʹͳΔ SE-XXXX: Function Builders

  25. • վߦ۠੾Γͷཁૉ͔ͨͪΒɺม਺એݴͱؔ਺ݺͼग़͠Λੜ੒͢Δ • @_functionBuilderΛ͚ͭͨstruct͸ɺFunction builderʹͳΔ SE-XXXX: Function Builders // @TupleBuilder͸

    // @_functionBuilderͱͯ͠Ͳ͔͜Ͱఆٛ @TupleBuilder func build() -> (Int, Int, Int) { 1 2 3 } func build() -> (Int, Int, Int) { let _a = 1 let _b = 2 let _c = 3 return TupleBuilder .buildBlock(_a, _b, _c) } ίϯύΠϥ͕ม׵
  26. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } ఆٛΛݟΔ
  27. public struct VStack<Content> : View where Content : View {

    @inlinable public init(
 alignment: HorizontalAlignment = .center, spacing: CGFloat? = nil, @ViewBuilder content: () -> Content) public typealias Body = Never } ఆٛΛݟΔ
  28. @_functionBuilder public struct ViewBuilder { public static func buildBlock<Content> (_

    content: Content) -> Content where Content : View } Ҿ਺1ݸͰɺͦΕͱಉ͡ܕͷViewΛฦ͍ͯ͠Δ
  29. extension ViewBuilder { public static func buildBlock<C0, C1> (_ c0:

    C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View } Ҿ਺2ݸͰɺͦΕͱಉ͡ܕͷTupleView<(C0, C1)>Λฦ͍ͯ͠Δ
  30. extension ViewBuilder { public static func buildBlock<C0, C1> (_ c0:

    C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View } Ҿ਺2ݸͰɺͦΕͱಉ͡ܕͷTupleView<(C0, C1)>Λฦ͍ͯ͠Δ ʹ74UBDLͷҾ਺ͷਖ਼ମ
  31. extension ViewBuilder { public static func buildBlock<C0, C1, C2>(_ c0:

    C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0 : View, C1 : View, C2 : View } 3ݸ൛
  32. extension ViewBuilder { public static func buildBlock<C0, C1, C2, C3>(_

    c0: C0, _ c1: C1, _ c2: C2, _ c3: C3) -> TupleView<(C0, C1, C2, C3)> where C0 : View, C1 : View, C2 : View, C3 : View } 4ݸ൛…
  33. extension ViewBuilder { public static func buildBlock<C0, C1, C2, C3,

    C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View, C9 : View } 10ݸ൛·Ͱ͋Δ
  34. extension ViewBuilder { public static func buildBlock<C0, C1, C2, C3,

    C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View, C9 : View } 10ݸ൛·Ͱ͋Δ ʹ10ݸ൛·Ͱ͔͠ͳ͍ ͦΕҎ্ฒ΂͍ͨͱ͖͸ɺ GroupΛ࢖͏͜ͱ
  35. struct ContentView: View { var body: some View { return

    VStack { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } ͭ·Γ͜ͷϒϩοΫ͸
  36. struct ContentView: View { var body: some View { return

    VStack { return ViewBuilder.buildBlock( Text(item.title), Text(item.subtitle) .foregroundColor(Color.gray) } } } } ͜͏ղऍ͞ΕΔ
  37. ฦΓ஋ͷܕ͸ $5FYU $5FYUͳͷͰɺ 5VQMF7JFX 5FYU 5FYU ʹͳΔ struct ContentView: View

    { var body: some View { return VStack { return ViewBuilder.buildBlock( Text(item.title), Text(item.subtitle) .foregroundColor(Color.gray) } } } }
  38. ฦΓ஋ͷܕ͸ɺ74UBDLͷܕύϥϝʔλ$POUFOUʹΑͬͯ 74UBDL5VQMF7JFX 5FYU 5FYU ʹͳΔ struct ContentView: View { var

    body: some View { return VStack { return ViewBuilder.buildBlock( Text(item.title), Text(item.subtitle) .foregroundColor(Color.gray) } } } }
  39. struct ContentView: View { var body: some View { let

    hoge = VStack { return ViewBuilder.buildBlock( Text(item.title), Text(item.subtitle) .foregroundColor(Color.gray) ) } return hoge } } ద౰ͳม਺ʹ୅ೖͯ͠ɺ PQU $MJDL͢Δͱɺ ܕΛ֬ೝ͢Δ͜ͱ͕Ͱ͖·͢
  40. @_functionBuilder public struct NumsBuilder { public static func buildBlock(_ nums:

    Int...) -> [Int] { nums } } func printNums(@NumsBuilder numsBuilder: () -> [Int]) { numsBuilder().forEach { print($0) } } printNums { 1 2 3 } ࣗ෼Ͱͭ͘Δ͜ͱ΋Ͱ͖Δ
  41. • Swift Evolution: SE-0255 • Implicit return from single expressions

    • Swift Evolution: SE-XXXX • Function builders (draft proposal) • Swift Evolution: SE-0244 • Opaque Result Type some View Λ࣮ݱ͢Δػೳ ͍͞͝ʂ
  42. Opaque Result Type

  43. • δΣωϦΫεͷΑ͏ͳ΋ͷ • some Protocol ͷΑ͏ͳܕ͕ Opaque Result Type •

    some View ͸
 ʮ۩ମతͳܕ͸ެ։͠ͳ͍͚ͲɺViewϓϩτίϧʹద߹ͨ͠ԿΒ͔ͷܕʯ
 Ͱ͋Δ͜ͱΛද͢ SE-0244: Opaque Result Type
  44. struct ContentView: View { var body: some View { return

    VStack { return ViewBuilder.buildBlock( Text(item.title), Text(item.subtitle) .foregroundColor(Color.gray) ) } } } 74UBDL5VQMF7JFX 5FYU 5FYU  ͷ࣮ࡍͷܕ͸ɺ ͨͱ͑͹ɺTPNF7JFX ͕ͩɺ֎ଆ͔Βݟͨͱ͖͸7JFXͱͯ͠ৼΔ෣͏
  45. struct ContentView: View { var body: VStack<TupleView<(Text, Text)>> { return

    VStack ( return ViewBuilder.buildBlock( Text(item.title), Text(item.subtitle) .foregroundColor(Color.gray) ) } } } ۩ମܕΛࢦఆͯ͠΋0,
  46. struct ContentView: View { var body: VStack<TupleView<(Text, Text)>> { return

    VStack ( return ViewBuilder.buildBlock( Text(item.title), Text(item.subtitle) .foregroundColor(Color.gray) ) } } } ۩ମܕΛࢦఆͯ͠΋0, ͜ͷܗͳΒɺ΋͸΍4XJGUະຬͷจ๏Ͱ΋ҙຯ͕௨Δ
  47. ϝϦοτ • ͖ͬ͢Γ͢Δ SE-0244: Opaque Result Type

  48. ϝϦοτ • ͖ͬ͢Γ͢Δ SE-0244: Opaque Result Type VStack<TupleView<(Text, Text)>> ͦΕ͚ͩͰ͸ͳ͍

    ʢ˞Computed property ͸ܕએݴΛলུͰ͖ͳ͍ʣ
  49. • ίϯύΠϧ࣌ʹԿΒ͔ͷܕͰ͋Δ͜ͱ͕֬ఆ͢Δ • ίϯύΠϧ࣌ʹ෼͔ΔͷͰɺ࣮ߦ࣌ʹύϑΥʔϚϯεϩε͕ͳ͍ SE-0244: Opaque Result Type

  50. SE-0244: Opaque Result Type func map<A, B>(l: List<A>, _ f:

    A -> B) -> List<B> { switch l { case .Nil: return .Nil case let .Cons(x, xs): return cons(f(x), map(xs, f)) } } [1,2].map { $0 * 2 } δΣωϦΫεͷܕ͸
 ֎ଆ͔Β࣮ࡍͷܕΛ
 ࢦఆͯ֬͠ఆ͢Δ Opaque Result Type Ͱ͸
 ಺ଆ͔Β࣮ࡍͷܕ͕֬ఆ͢Δ *OU*OU struct ContentView: View { var body: some View { VStack { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } 74UBDL 5VQMF7JFX 5FYU 5FYU 
  51. struct ContentView: View { var body: View { VStack {

    Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } 7JFX͸QSPUPDPMͰɺ BTTPDJBUFEUZQFΛ΋ͭͷͰɺ ͜͏͸ॻ͚ͳ͍
  52. struct ContentView: View { var body: AnyView { AnyView(VStack {

    Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) }) } } ܕফڈ͸Ͱ͖Δ͕ɺ ύϑΥʔϚϯεϩε͕͋Δ
  53. • Swift Evolution: SE-0255 • Implicit return from single expressions

    • Swift Evolution: SE-XXXX • Function builders (draft proposal) • Swift Evolution: SE-0244 • Opaque Result Type some View Λ࣮ݱ͢Δػೳ
  54. ·ͱΊ

  55. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } SFUVSO͸ ࣜͭͳΒলུՄೳ
  56. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } SFUVSO͸ ࣜͭͳΒলུՄೳ 'VODUJPO#VJMEFSʹΑͬͯɺ 7JFX#VJMEFSCVJME#MPDL 5FYU 5FYU ͱղऍ͞ΕΔ ࣮ࡍͷܕ͸ɺ74UBDL5VQMF7JFX 5FYU 5FYU 
  57. struct ContentView: View { var body: some View { VStack

    { Text(item.title) Text(item.subtitle) .foregroundColor(Color.gray) } } } TPNF7JFX͸ 7JFXʹద߹͢Δ ԿΒ͔ͷܕͰ͋Δ͜ͱΛࣔ͢ 'VODUJPO#VJMEFSʹΑͬͯɺ 7JFX#VJMEFSCVJME#MPDL 5FYU 5FYU ͱղऍ͞ΕΔ ࣮ࡍͷܕ͸ɺ74UBDL5VQMF7JFX 5FYU 5FYU  SFUVSO͸ ࣜͭͳΒলུՄೳ
  58. ୈҰ෦ some Viewฤ ׬

  59. ୈೋ෦ Property Wrappers ฤ

  60. None
  61. None
  62. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } #PPMܕͷ ϓϩύςΟ
  63. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } #PPMܕͷ ϓϩύςΟ UPHHMFΛͻͱͭ ΋ͭ7JFX
  64. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } #PPMܕͷ ϓϩύςΟ UPHHMFΛͻͱͭ ΋ͭ7JFX JT0OͳΒl0Oz JT0OͳΒl0⒎
  65. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } !4UBUF ͬͯԿʁ
  66. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } JT0O ͬͯԿʁ !4UBUF ͬͯԿʁ
  67. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } JT0O ͬͯԿʁ !4UBUF ͬͯԿʁ QSPKFDUFE7BMVFΛ ฦ͢ԋࢉࢠ 1SPQFSUZ8SBQQFS
  68. • Swift Evolution: SE-0258 • Property Wrappers ViewόΠϯσΟϯάΛ࣮ݱ͢Δػೳ

  69. • ϓϩύςΟʔͷϥούʔ • தʹਅͷ஋͕แ·Ε͍ͯΔΠϝʔδ • ϓϩύςΟͷsetterͱgetterΛݺΜͩͱ͖ʹ͍ͨ͠ॲཧΛɺ
 ผΫϥεʹҠৡ͢ΔσβΠϯύλʔϯΛ
 ίϯύΠϥʔϨϕϧͰఏڙͯ͘͠ΕΔػೳ • Kotlin

    ͷ Delegated Properties ͱࣅ͍ͯΔ Property Wrappers
  70. struct Foo { private var _foo: Int? var foo: Int

    { get { if let value = _foo { return value } let initialValue = 1738 _foo = initialValue return initialValue } set { _foo = newValue } } } ஗ԆධՁ͢Δ ܭࢉܕϓϩύςΟ MB[ZWBSGPP ͱ͓ͳ͡ ܭࢉܕϓϩύςΟʹ ౎౓ܭࢉͯ͠ ݁ՌΛฦͨ͠Γ HFU  ઃఆͨ͠ΓʢTFUʣ ͢Δ΋ͷ
  71. struct Foo { private var _foo: Int? var foo: Int

    { get { if let value = _foo { return value } let initialValue = 1738 _foo = initialValue return initialValue } set { _foo = newValue } } } ௕͍͠ଟ͍
  72. @propertyWrapper enum Lazy<Value> { case uninitialized(() -> Value) case initialized(Value)

    init(wrappedValue: @autoclosure @escaping () -> Value) { self = .uninitialized(wrappedValue)} var wrappedValue: Value { mutating get { switch self { case .uninitialized(let initializer): let value = initializer() self = .initialized(value) return value case .initialized(let value): return value }} set { self = .initialized(newValue) } }} δΣωϦΫε൛Λ࡞ͬͯ TFUUFSͱHFUUFSɺ όοΩϯάϑΟʔϧυ ʢXSBQQFE7BMVFʣ ʹؔ͢Δ৘ใΛɺ 1SPQFSUZ8SBQQFS ʹԡ͠ࠐΊΕ͹ʜ
  73. class Foo { @Lazy var foo: Int = 1738 }

    ࢖͏ଆ͸͖ͬ͢Γʂ
  74. class Foo { @Lazy var foo: Int = 1738 }

    private var _foo: Lazy<Int> = Lazy<Int>(wrappedValue: 1738) var foo: Int { get { return _foo.wrappedValue } set { _foo.wrappedValue = newValue } } ࣮ࡍʹ͸͜Μͳײ͡ͷίʔυʹల։͞ΕΔ
  75. @propertyWrapper // ͱ͘ʹҙຯ͸ͳ͍ struct Nyan<Int> { ... var projectedValue: String

    { return "ʹΌʔΜ" } } QSPKFDUFE7BMVF͕͋Ε͹
  76. class Hoge { @Nyan var foo: Int = 1738 func

    meow() { print($foo) } } Hoge().meow() // ʹΌʔΜ ͰऔΓग़ͤΔ ※ projectedValue ͕ఆٛ͞Εͯͳ͚Ε͹ Use of unresolved identifier ‘$foo’ ʹͳΓ·ͨ͠ (Xcode 11 GM Seed1)
  77. • Property wrapper Ͱ͸
 ϓϩύςΟʹؔ͢ΔॲཧΛଞͷܕʹҠৡͰ͖Δ • @Hoge var foo: Int

    ͱॻ͘ͱ
 var _foo: Hoge<Int> ͱ var foo: Int ʹల։͞ΕΔ • foo ͸ _foo.wrappedValue ͱ౳Ձ • $foo ͸ _foo.projectedValue ͱ౳Ձ • SwiftUIͰ͸Ͳ͏͍͏;͏ʹ࢖ΘΕ͍ͯΔͷ͔ʁ Property Wrapper ·ͱΊ
  78. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } ͜Ε͸ 1SPQFSUZ8SBQQFS
  79. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } ͜Ε͸ 1SPQFSUZ8SBQQFS ී௨ʹݺͿͱ XSBQQFE7BMVF͕औΕΔ
  80. struct ContentView: View { @State var isOn: Bool var body:

    some View { Toggle(isOn: $isOn) { if self.isOn { Text("On") } else { Text("Off") } }.frame(width: 200) } } ͜Ε͸ 1SPQFSUZ8SBQQFS ී௨ʹݺͿͱ XSBQQFE7BMVF͕औΕΔ ԋࢉࢠͰ QSPKFDUFE7BMVF͕औΕΔ
  81. มߋΛݕ஌ɾ௨஌͢Δ #JOEJOH7BMVF /// A linked View property that instantiates a

    persistent state /// value of type `Value`, allowing the view to read and update its /// value. @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) @propertyWrapper public struct State<Value> : DynamicProperty { /// Initialize with the provided initial value. public init(wrappedValue value: Value) /// Initialize with the provided initial value. public init(initialValue value: Value) /// The current state value. public var wrappedValue: Value { get nonmutating set } /// Produces the binding referencing this state value public var projectedValue: Binding<Value> { get } }
  82. • Property wrapperͰget/set࣌ʹΠϕϯτͷൃߦΛߦ͏͜ͱʹΑΓɺ
 ஋ͷಉظ΍View΁ͷόΠϯσΟϯάΛՄೳʹ͍ͯ͠Δʢ˞ʣ • $ Ͱ Binding<Value>͕औΓग़ͤΔ • Binding<Value>ΛViewʹ౉͢ͱɺViewʹόΠϯσΟϯά͞ΕΔ


    ʢมߋͨ͠ͱ͖ʹΠϕϯτΛൃߦͨ͠Γɺ
 ɹมߋΛݕ஌ͯ͠Viewʹ൓өͯ͘͠ΕͨΓ͢Δʣ SwiftUIͰ͍ͯ͠Δ͜ͱ ·ͱΊ ʢ˞ʣਪଌɻIF΍υΩϡϝϯτɺWWDCͷηογϣϯͷ಺༰ͳͲ͔Βਪଌ͢Δ͔͠ͳ͍
  83. • ެࣜ࡞ྫ • UserDefaults • Clamping • ϥΠϒϥϦ • ValidatedPropertyKit

    • DIAttribute ྫΛ৭ʑΈͯΠϝʔδΛ͔ͭ΋͏
  84. enum GlobalSettings { @UserDefault(key: "FOO_FEATURE_ENABLED", defaultValue: false) static var isFooFeatureEnabled:

    Bool @UserDefault(key: "BAR_FEATURE_ENABLED", defaultValue: false) static var isBarFeatureEnabled: Bool } User Defaults ม਺ʹॻ͘ϊϦͰӬଓԽ
  85. @propertyWrapper struct UserDefault<T> { let key: String let defaultValue: T

    var wrappedValue: T { get { return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue } set { UserDefaults.standard.set(newValue, forKey: key) } } } γϯϓϧ ʢγϯϓϧ͗ͯ͢ෆཁઆ΋͋Δʣ User Defaultsʢ࣮૷ʣ
  86. Clamping struct Color { @Clamping(min: 0, max: 255) var red:

    Int = 127 @Clamping(min: 0, max: 255) var green: Int = 127 @Clamping(min: 0, max: 255) var blue: Int = 127 @Clamping(min: 0, max: 255) var alpha: Int = 255 } ஋Λ<NJO NBY> ʹ·ΔΊͯ͘ΕΔ
  87. var wrappedValue: V { get { return value } set

    { if newValue < min { value = min } else if newValue > max { value = max } else { value = newValue } } } @propertyWrapper struct Clamping<V: Comparable> { var value: V let min: V let max: V init(wrappedValue: V, min: V, max: V) { value = wrappedValue self.min = min self.max = max assert(value >= min && value <= max) } Clampingʢ࣮૷ʣ
  88. • SvenTiigi/ValidatedPropertyKit • https://github.com/SvenTiigi/ValidatedPropertyKit • @Validated(.isEmail)Ͱ
 EϝʔϧΞυϨεͷόϦσʔγϣϯ͕Ͱ͖ͨΓ͢Δ • γϯϓϧ SvenTiigi/ValidatedPropertyKit

  89. SvenTiigi/ValidatedPropertyKit @Validated(.nonEmpty) var username: String? @Validated(.isEmail) var email: String? @Validated(.range(8...))

    var password: String? @Validated(.greaterOrEqual(1)) var friends: Int? @Validated(.isURL && .hasPrefix("https")) var avatarURL: String?
  90. SvenTiigi/ValidatedPropertyKit @Validated(.nonEmpty) var username: String? @Validated(.isEmail) var email: String? @Validated(.range(8...))

    var password: String? @Validated(.greaterOrEqual(1)) var friends: Int? @Validated(.isURL && .hasPrefix("https")) var avatarURL: String? &ϝʔϧͷܗࣜͳΒ&ϝʔϧɺ ෆਖ਼ͳܗࣜͳΒOJMʹͳΔ
  91. • tattn/DIAttribute • https://github.com/tattn/DIAttribute • AndroidͷDaggerͷΑ͏ͳΞϊςʔγϣϯϕʔεͰDIΛ࣮ݱ͢ΔϥΠ ϒϥϦ • γϯϓϧ tattn/DIAttribute

  92. tattn/DIAttribute DIResolver.register(ViewController.self, keyPath: \.apiClient, value: ProductionAPIClient()) DIResolver.register(ViewController.self, keyPath: \.apiClient, value:

    MockAPIClient())
  93. tattn/DIAttribute final class ViewController: UIViewController { @Inject(Self.self) var apiClient: APIClientProtocol

    } %*3FTPMWFSSFHJTUFSͰ ొ࿥ͨ͠஋͕࢖ΘΕΔ
  94. import Foundation @propertyWrapper public struct Inject<Target, Value> { public init(_

    type: Target.Type) {} public var wrappedValue: Value { DIResolver.resolve(Target.self)! } } SFTPMWFΛୟ͍͍ͯΔ͚ͩ
  95. SFHJTUFSͨ͠ͱ͖ʹ%*3FTPMWFS͕ΫϩʔδϟΛอ͓࣋ͯ͠Γɺ SFTPMWFͰ͸ɺอ࣋ͨ͠ΫϩʔδϟΛධՁͯ͠ฦ͢ public struct DIResolver { private static var factories:

    [ObjectIdentifier: [ObjectIdentifier: Factory<Any>]] = [:] public static func resolve<Target, Value>( _ target: Target.Type = Target.self, value: Value.Type = Value.self) -> Value? { factories[.init(target)]?[.init(value)]?() as? Value } }
  96. ୈೋ෦ Property Wrappers ฤ ׬

  97. SwiftUI ͸Swift5.1ͷػೳʹΑ͖ͬͯͬ͢Γॻ͚ΔΑ͏ʹͳ͍ͬͯΔ • Swift Evolution: SE-0255: Implicit return from single

    expressions • Swift Evolution: SE-XXXX :Function builders • Swift Evolution: SE-0244: Opaque Result Type • Swift Evolution: SE-0258: Property Wrappers • ܅΋܅͚ͩͷ
 ࠷ڧͷFunction Builders / Property WrappersΛ࡞ͬͯಆ͓͏ʂ ·ͱΊ
  98. • Swift Evolution • https://github.com/apple/swift-evolution/blob/master/proposals/0255-omit-return.md • https://github.com/apple/swift-evolution/blob/9992cf3c11c2d5e0ea20bee98657d93902d5b174/proposals/XXXX- function-builders.md • https://github.com/apple/swift-evolution/blob/master/proposals/0244-opaque-result-types.md

    • https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md# References
  99. • SwiftUIͷຐ๏Λ࣮ݱ͢Δ࢓૊Έ (Custom Attributes, Function Builder) • https://qiita.com/kentrino/items/dc6e77a0ddd21187cc55 • SwiftUIͷίʔυΛಡΈղ͘

    • https://blog.personal-factory.com/2019/06/07/understand-swiftui-code/ • Swift 5.1 ʹಋೖ͞ΕΔ Opaque Result Type ͱ͸Կ͔ • https://qiita.com/koher/items/338d2f2d0c4731e3508f • Opaque Result Typeͷղઆ • https://qiita.com/omochimetaru/items/f13fe3e54fab01648ba4 • SwiftUIͰ࢖༻͞Ε͍ͯΔSwift5.1ͷ৽ػೳ - ΫοΫύου։ൃऀϒϩά • https://techlife.cookpad.com/entry/2019/06/25/120000Qa • SwiftUIͷProperty Wrappersͱσʔλ΁ͷΞΫηεํ๏ • https://qiita.com/shiz/items/6eaf87fa79499623306a See Also
  100. Enjoy SwiftUI!