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

SwiftUIで勘違いした話

 SwiftUIで勘違いした話

最近、本格的にSwiftUIを触り始めたところ、この前、盛大に勘違いしてやらかしてしまいました。その経緯と関連するトピックがおもしろかったので紹介します。

どこで勘違いしてしまったか考えながら見てみて下さい。

Yuta Koshizawa

July 10, 2020
Tweet

More Decks by Yuta Koshizawa

Other Decks in Technology

Transcript

  1. @koher • try! Swi* Tokyo • 2016, 2018 • iOSDC

    Japan • 2017, 2018, 2019 • Qiita • "Swi*ͷOp?onalܕΛۃΊΔ" • "JavaϓϩάϥϚͷͨΊͷKotlinೖ໳" • ...
  2. struct CounterView: View { @State var count: Int = 0

    var body: some View { VStack { Text("\(count)") .font(.largeTitle) Stepper("count", value: $count) .labelsHidden() } } }
  3. struct CounterView: View { @State var count: Int = 0

    var body: some View { VStack { Text("\(count)") .font(.largeTitle) Stepper("count", value: $count) .labelsHidden() } } }
  4. SE-0258: Property Wrappers1 Status: Implemented (Swi. 5.1) • @State •

    @ObservedObject • @Binding • @Published • ... 1 h$ps:/ /github.com/apple/swi6-evolu9on/blob/master/proposals/0258-property-wrappers.md
  5. projectedValue2 $count Property Wrapper projectedValue @State Binding<Value> @Binding Binding<Value> @Published

    Published<Value>.Publisher 2 h$ps:/ /docs.swi/.org/swi/-book/LanguageGuide/Proper<es.html#ID619
  6. struct CounterView: View { @State var count: Int = 0

    var body: some View { VStack { Text("\(count)") .font(.largeTitle) Stepper("count", value: $count) .labelsHidden() } } }
  7. struct CounterView: View { @State var count: Int = 0

    var body: some View { VStack { Text("\(count)") .font(.largeTitle) Stepper("count", value: $count) .labelsHidden() } } }
  8. struct CounterView: View { @State var count: Int = 0

    var body: some View { VStack { Text("\(count)") .font(.largeTitle) Stepper("count", value: $count) .labelsHidden() } } }
  9. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { Text("\(counter.count)") .font(.largeTitle) Stepper("count", value: $counter.count) .labelsHidden() } } }
  10. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { Text("\(counter.count)") .font(.largeTitle) Stepper("count", value: $counter.count) .labelsHidden() } } }
  11. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { Text("\(counter.count)") .font(.largeTitle) Stepper("count", value: $counter.count) .labelsHidden() } } }
  12. struct NumberDisplay: View { @Binding var number: Int var body:

    some View { return HStack { ForEach(digits(from: number)) { Image(systemName:"\($0.value).circle.fill") .resizable() .frame(width: 64, height: 64) } } } ... }
  13. struct NumberDisplay: View { @Binding var number: Int var body:

    some View { return HStack { ForEach(digits(from: number)) { Image(systemName:"\($0.value).circle.fill") .resizable() .frame(width: 64, height: 64) } } } ... }
  14. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: $counter.count) Stepper("count", value: $counter.count) .labelsHidden() } } }
  15. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: $counter.count) Stepper("count", value: $counter.count) .labelsHidden() } } }
  16. import Combine final class Counter: ObservableObject { @Published private(set) var

    count: Int = 0 func increment() { count += 1 } func reset() { count = 0 } }
  17. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: $counter.count) // HStack { Button("Reset") { self.counter.reset() } Button("Increment") { self.counter.increment() } } } } }
  18. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: $counter.count) // HStack { Button("Reset") { self.counter.reset() } Button("Increment") { self.counter.increment() } } } } }
  19. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: $counter.count) // HStack { Button("Reset") { self.counter.reset() } Button("Increment") { self.counter.increment() } } } } }
  20. SE-0195: Introduce User-defined "Dynamic Member Lookup" Types 5 Status: Implemented

    (Swi. 4.2) @dynamicMemberLookup enum JSON { ... subscript(dynamicMember member: String) -> JSON? { ... } } 5 h$ps:/ /github.com/apple/swi6-evolu9on/blob/master/proposals/0195-dynamic-member-lookup.md
  21. SE-0252: Key Path Member Lookup6 Status: Implemented (Swi. 5.1) @dynamicMemberLookup

    struct Lens<T> { ... subscript<U>(dynamicMember keyPath: WritableKeyPath<T, U>) -> Lens<U> { ... } } 6 h$ps:/ /github.com/apple/swi6-evolu9on/blob/master/proposals/0252-keypath-dynamic-member-lookup.md
  22. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: $counter.count) // HStack { Button("Reset") { self.counter.reset() } Button("Increment") { self.counter.increment() } } } } }
  23. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: $counter.readOnly // .count) HStack { Button("Reset") { self.counter.reset() } Button("Increment") { self.counter.increment() } } } } }
  24. ObservedObject.Wrapper.ReadOnly extension ObservedObject.Wrapper { var readOnly: ReadOnly { return ReadOnly(unsafeBitCast(self,

    to: ObjectType.self)) // } @dynamicMemberLookup struct ReadOnly { private let object: ObjectType init(_ object: ObjectType) { self.object = object } subscript<Subject>(dynamicMember keyPath: KeyPath<ObjectType, Subject>) -> Binding<Subject> { Binding<Subject>( get: { self.object[keyPath: keyPath] }, set: { _ in assertionFailure("Read-only") } ) } } }
  25. One-way data binding from @ObservedObject with Swi9UI7 Is it possible

    to achieve one-way data binding with Swi6UI in situa9ons like below? import Combine final class Counter: ObservableObject { @Published private(set) var count: Int = 0 func increment() { count += 1 } func reset() { count = 0 } } ... 7 h$ps:/ /forums.swi1.org/t/one-way-data-binding-from-observedobject-with-swi1ui/37547
  26. struct NumberDisplay: View { @Binding var number: Int var body:

    some View { return HStack { ForEach(digits(from: number)) { Image(systemName:"\($0.value).circle.fill") .resizable() .frame(width: 64, height: 64) } } } ... }
  27. struct NumberDisplay: View { let number: Int var body: some

    View { return HStack { ForEach(digits(from: number)) { Image(systemName:"\($0.value).circle.fill") .resizable() .frame(width: 64, height: 64) } } } ... }
  28. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: $counter.readOnly .count) HStack { Button("Reset") { self.counter.reset() } Button("Increment") { self.counter.increment() } } } } }
  29. struct CounterView: View { @ObservedObject var counter: Counter var body:

    some View { VStack { NumberDisplay(number: counter.count) HStack { Button("Reset") { self.counter.reset() } Button("Increment") { self.counter.increment() } } } } }