Continuing from my previous question, what is the best way to observe several state changes from a UIViewRepresentable? Previously, I required to only observe changes to one property userWon. However, as new functionality was introduced in the app, I need to now observe new changes. Assuming these could increase even more, is the best way to do this by adding more State properties and binding them to the UIViewRepresentable? It feels somewhat hacky at this point to add more and more bindings and onChange modifiers to observe for changes.
Example code is as follows:
struct GameView: View {
@State private var userWon: Bool = false
@State private var propA: Bool = false
@State private var propB: Int = 0
@State private var propC: Int = 0
...
...
...
@State private var propZ: Int = 0
@StateObject private var gameService = GameService()
var body: some View {
ZStack {
VStack {
GameViewRepresentable(userWon: $userWon,
propA: $propA,
propB: $propB,
propC: $propC,
...
propZ: $propZ) // <- Add more bindings??
.onChange(of: userWon) { newValue in
if newValue {
gameService.updateUserScore()
}
}
.onChange(of: propA) { newValue in
gameService.doSomethingA()
}
.onChange(of: propB) { newValue in
gameService.doSomethingB()
}
.onChange(of: propZ) { newValue in
gameService.doSomethingZ()
}
}
.clipped()
}
}
}
struct GameViewRepresentable: UIViewRepresentable {
typealias UIViewType = GameView
@Binding var userWon: Bool
func makeUIView(context: Context) -> GameView {
let gameView = GameView()
gameView.delegate = context.coordinator
return gameView
}
func updateUIView(_ uiView: GameView, context: Context) {
}
func makeCoordinator() -> GameViewCoordinator {
GameViewCoordinator(self)
}
class GameViewCoordinator: GameViewDelegate {
var parent: GameViewRepresentable
init(_ parent: GameViewRepresentable) {
self.parent = parent
}
func userWon() {
self.parent.userWon = true
}
}
}
Alternate approach that I can think of is:
- Create an envelope object/model in
gameServicethat contains the aforementioned properties to be observed and pass that as binding to theUIViewRepresentable. - Have
gameServiceobserve this enveloped object, probably usingCombine? for changes but I'm not sure how to do this or if it'd work at all. Any help is appreciated on how to do this efficiently.
GameViewModelas@Published vars.onChangein the view.GameViewRepresentable. If you could split it up into multiple SwiftUI views that has their own state, you wouldn't need so many@Statein the parent. The views can then interact with the game model through an@EnvironmentObjector similar.