1

I have one View and two classes (Cls1 and Cls2).

Object of Class1 initialised in view like:

@ObservedObject var cls1 = Cls1()

And I have no problems to get variables of clsObj declaring them inside class as:

@Published var myVarFromCls1 = false

However, I have Cls2, it was initialised inside Cls1:

var cls2 = Cls2()

and I need to get changes in variables of cls2 inside my view.

I've tried to redeclare cls2 initialization to:

@Published var cls2 = Cls2()

But I can't get its variable in view using:

@ObservedObject var cls1 = Cls1()
$cls1.cls2.myVarFromCls2

declared in Class2:

@Published var myVarFromCls2 = false

How to do it right way?

Alex Zaitsev
  • 690
  • 6
  • 17

1 Answers1

0

At the end of Cls1's initializer, add:

  cancellable = cls2.objectWillChange.forwardedThroughObjectWillChange(of: self)
}

private var cancellable: AnyCancellable!
import Combine

public extension Publisher<Void, Never> {
  /// Forward output through an  `ObservableObject`'s `objectWillChange`.
  func forwardedThroughObjectWillChange<Object: ObservableObject>(of object: Object) -> AnyCancellable
  where Object.ObjectWillChangePublisher == ObservableObjectPublisher {
    sink { [unowned object] in object.objectWillChange.send() }
  }
}

You can use the same idea for e.g. "[some ObservableObject]" situations.

import Combine
import SwiftUI

@propertyWrapper
public final class ObservableObjects<Objects: Sequence>: ObservableObject
where
  Objects.Element: ObservableObject,
  Objects.Element.ObjectWillChangePublisher == ObservableObjectPublisher
{
  public init(wrappedValue: Objects) {
    self.wrappedValue = wrappedValue
    assignCancellable()
  }

  @Published public var wrappedValue: Objects {
    didSet { assignCancellable() }
  }

  private var cancellable: AnyCancellable!
}

// MARK: - private
private extension ObservableObjects {
  func assignCancellable() {
    cancellable = Publishers.MergeMany(wrappedValue.map(\.objectWillChange))
      .forwardedThroughObjectWillChange(of: self)
  }
}

// MARK: -

@propertyWrapper
public struct ObservedObjects<Objects: Sequence>: DynamicProperty
where
  Objects.Element: ObservableObject,
  Objects.Element.ObjectWillChangePublisher == ObservableObjectPublisher
{
  public init(wrappedValue: Objects) {
    _objects = .init(
      wrappedValue: .init(wrappedValue: wrappedValue)
    )
  }

  public var wrappedValue: Objects {
    get { objects.wrappedValue }
    nonmutating set { objects.wrappedValue = newValue }
  }

  public var projectedValue: Binding<Objects> { $objects.wrappedValue }

  @ObservedObject private var objects: ObservableObjects<Objects>
}

@propertyWrapper
public struct StateObjects<Objects: Sequence>: DynamicProperty
where
  Objects.Element: ObservableObject,
  Objects.Element.ObjectWillChangePublisher == ObservableObjectPublisher
{
  public init(wrappedValue: Objects) {
    _objects = .init(
      wrappedValue: .init(wrappedValue: wrappedValue)
    )
  }

  public var wrappedValue: Objects {
    get { objects.wrappedValue }
    nonmutating set { objects.wrappedValue = newValue }
  }

  public var projectedValue: Binding<Objects> { $objects.wrappedValue }

  @StateObject private var objects: ObservableObjects<Objects>
}