4

I have a graphical user interface made of several SwiftUI components (lets call them subviews). These subviews communicate with each other with the help of ObservableObject / ObservedObject. When changes are made to one view, the other view is automatically notified and updates itself.

However, one of the subviews is not a SwiftUI view but a SpriteKit SKScene. Here, too, I would like to react to the changes in an observed value. But I do not have a view that updates automatically. I want to make adjustments to the sprites, depending on the observed value.

How can I be notified of changes in the value? Can I call a method as soon as the value of the ObservedObject changes?

TalkingCode
  • 13,407
  • 27
  • 102
  • 147
  • Have you made attempts to make a SKView available in SwiftUI, like in this basic tutorial: https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit. Then, it's not clear what kind of object you want to render in a SKView other than the SKScene. – CouchDeveloper Apr 27 '21 at 10:46

1 Answers1

9

It is easy to observe changes in ObservedObject from UIKit or SKScene. The example below is from UIViewController, change this for the equivalent to SKScene:

import Combine

class Object: ObservableObject { 
    @Published var value: Int = 10
    @Published var anotherValue: String = "Hello"
}

class MyViewController: UIViewController { 

    let observedObject = Object()
    var cancellableBag = Set<AnyCancellable>()

    override func viewDidLoad() { 
        super.viewDidLoad()

        // REACT TO ANY @PUBLISHED VARIABLE
        observedObject.objectWillChange.sink { 
              // Do what you want here
        }.store(in: &cancellableBag)

        // REACT ONLY TO ONE SPECIFIED @PUBLISHED VARIABLE
        observedObject.$value.sink { value in
              // Do what you want here
        }.store(in: &cancellableBag)
    }
}

Note that @Published is a propertyWrapper with projectedValue. The projectedValue in this case is the Publisher, that emits events every time the wrappedValue will be changed, so in order to access to the projectedValue it is necessary to call $value instead of value.

AlbertUI
  • 1,409
  • 9
  • 26
  • 2
    Also note, that this publisher is emitted **prior** to the value being changed (ie. objectWillChange). If you attempt to access the value of the property through the ObservableObject it will still have old value. – lipka Nov 21 '22 at 12:28
  • @lipka When you observe the ObservableObject's 'objectWillChange' yes, you have the old state and you cannot capture the new value because you get a Void () function when you attemp to get it from the closure. But, in the second case, when you observe a concrete value you get that future value inside the closure. – AlbertUI Nov 22 '22 at 13:20