I have an Updater
class that uses Combine
to check a state then update another state. If I initialize the Updater
in a view it works fine but it is initilized again each time the View is redrawn. If I initialize the Updater
outside the View the Combine process isn’t called when the state updates, i.e. sink
is only called one, not when firstCount
is updated.
The Updater class that uses Combine
:
class Updater {
private var cancellables = Set<AnyCancellable>()
func setup(appState: AppState) {
CurrentValueSubject<Int, Never>(appState.firstCount)
.map {
$0 * 10
}
.sink { value in
print("Sink (value)")
DispatchQueue.main.async {
appState.resultCount = value
}
}
.store(in: &cancellables)
}
}
The State:
@Observable class AppState {
var firstCount: Int = 0
var resultCount: Int = 0
}
The App struct that initializes the BackgroundTask
:
@main
struct TestCombineInViewApp: App {
var appState: AppState = AppState()
private let updater: Updater
init() {
let appState = AppState()
self.appState = appState
updater = Updater()
updater.setup(appState: appState)
}
var body: some Scene {
WindowGroup {
ContentView(appState: appState)
}
}
}
The view:
struct ContentView: View {
@State private var appState: AppState
init(appState: AppState) {
self.appState = appState
}
var body: some View {
VStack {
Text("first Count: (appState.firstCount)")
Text("Result Count: (appState.resultCount)")
Button {
appState.firstCount += 1
} label: {
Text("Plus")
}
}
}
}
The resultCount
should be updated each time firstCount
is updated via the Button
.
I’m guessing that Cancellables must be created inside the View hierarchy, but I don’t really follow how this works.