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

Resolve Nested ObservableObject issues in Obser...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for elmetal elmetal PRO
November 01, 2023

Resolve Nested ObservableObject issues in Observation

ObservableObjectをプロパティに持つObsevableObjectはCombineの監視の仕組み上問題があります。Observationでは、Combineの監視とは異なる手段で監視することでこの問題を解決しています。
CombineとObservationの監視の仕組みの違いを見て、元の問題がどう解決されるかを紹介します。

Avatar for elmetal

elmetal PRO

November 01, 2023
Tweet

More Decks by elmetal

Other Decks in Programming

Transcript

  1. final class Parent: ObservableObject { @Published var child: Child init(child:

    Child) { self.child = child } } final class Child: ObservableObject { @Published var age: Int init(age: Int) { self.age = age } func haveBirthday() { age += 1 } } /FTUFE0CTFSWBCMF0CKFDU 3FQSPEVDFUIFJTTVFPG0CTFSWBCMF0CKFDU
  2. /FTUFE0CTFSWBCMF0CKFDU 3FQSPEVDFUIFJTTVFPG0CTFSWBCMF0CKFDU final class Parent: ObservableObject { @Published var child:

    Child init(child: Child) { self.child = child } } final class Child: ObservableObject { @Published var age: Int init(age: Int) { self.age = age } func haveBirthday() { age += 1 } } struct BirthdayView: View { @StateObject var parent = Parent(child: Child(age: 1)) var body: some View { Text("child is \(parent.child.age) years old") Button("Have Birthday", action: { parent.child.haveBirthday() }) } }
  3. final class Parent: ObservableObject { @Published var child: Child private

    var cancellables = Set<AnyCancellable>() init(child: Child) { self.child = child child.objectWillChange.sink { [weak self] in self?.objectWillChange.send() } .store(in: &cancellables) } } final class Child: ObservableObject { @Published var age: Int init(age: Int) { self.age = age } func haveBirthday() { age += 1 } } /FTUFE0CTFSWBCMF0CKFDU 'JYUIFJTTVFPG0CTFSWBCMF0CKFDU
  4. final class Parent: ObservableObject { @Published var child: Child private

    var cancellables = Set<AnyCancellable>() init(child: Child) { self.child = child child.objectWillChange.sink { [weak self] in self?.objectWillChange.send() } .store(in: &cancellables) } } final class Child: ObservableObject { @Published var age: Int init(age: Int) { self.age = age } func haveBirthday() { age += 1 } } struct BirthdayView: View { @StateObject var parent = Parent(child: Child(age: 1)) var body: some View { Text("child is \(parent.child.age) years old") Button("Have Birthday", action: { parent.child.haveBirthday() }) } } /FTUFE0CTFSWBCMF0CKFDU 'JYUIFJTTVFPG0CTFSWBCMF0CKFDU
  5. @Observable final class Parent { var child: Child init(child: Child)

    { self.child = child } } @Observable final class Child { var age: Int init(age: Int) { self.age = age } func haveBirthday() { age += 1 } } /FTUFE!0CTFSWBCMF 8JMMUIFJTTVFCFSFQSPEVDFE
  6. 5IFJTTVFJTSFTPMWFE @Observable final class Parent { var child: Child init(child:

    Child) { self.child = child } } @Observable final class Child { var age: Int init(age: Int) { self.age = age } func haveBirthday() { age += 1 } } struct BirthdayView: View { @State var parent = Parent(child: Child(age: 1)) var body: some View { Text("child is \(parent.child.age) years old") Button("Have Birthday", action: { parent.child.haveBirthday() }) } } /FTUFE!0CTFSWBCMF
  7. *OMJOF!0CTFSWBCMF.BDSP final class Child { @ObservationTracked var age: Int init(age:

    Int) { self.age = age } func haveBirthday() { age += 1 } @ObservationIgnored private let _$observationRegistrar = Observation.ObservationRegistrar() internal nonisolated func access<Member>( keyPath: KeyPath<Child , Member> ) { _$observationRegistrar.access(self, keyPath: keyPath) } internal nonisolated func withMutation<Member, MutationResult>( keyPath: KeyPath<Child , Member>, _ mutation: () throws -> MutationResult ) rethrows -> MutationResult { try _$observationRegistrar.withMutation(of: self, keyPath: keyPath, mutation) } } extension Child: Observation.Observable { }
  8. *OMJOF!0CTFSWBUJPO5SBDLFE.BDSP final class Child { var age: Int{ @storageRestrictions(initializes: _age)

    init(initialValue) { _age = initialValue } get { access(keyPath: \.age) return _age } set { withMutation(keyPath: \.age) { _age = newValue } } } … }