Reputation: 3498
I have a simple Loader that performs a loading animation when its @Publisher is set to true. This publisher is set to true on a ViewModel when making a network request. I would like this value to change my view, which it doesn't. The ContentView shown is more complex with many views inside each other, but it is the root view of them all. And the loader is a Lottie view that works perfectly when everything is set to true manually. The Loader is a stand-alone @ObservableObject as I want to use it in many others ViewModels.
Why is my @ObservedObject var loader
not performing any change in my view state when set from a ViewModel?
My loader:
final class Loader: ObservableObject {
@Published var isLoading = false
}
My view model which trigger the loader: (In the console, the values of the loader are changing accordingly)
final class OnboardingViewModel: ObservableObject {
@ObservedObject var loader = Loader()
func demoLogin() {
loaderIsLoading(true) // loader set to true
AuthRequest.shared
.demoLogin()
.sink(
receiveCompletion: {
self.loaderIsLoading(false) }, // loader set to false
receiveValue: {
self.enterDemoAction()
print("Login: \($0.login)\nToken: \($0.token)") })
.store(in: &subscriptions)
}
func loaderIsLoading(_ action: Bool) {
DispatchQueue.main.async {
self.loader.isLoading = action
}
}
}
This is the SwiftUI view where I want the magic happens: (It is much more complicated than this with subviews and components inside each other)
struct ContentView: View {
@EnvironmentObject var onboardingViewModel: OnboardingViewModel
@ObservedObject var loader = Loader()
var body: some View {
ZStack {
if loader.isLoading { // this is where it is not updated
LottieView(named: .loading,
loop: loader.isLoading,
width: 220, height: 220)
}
}
}
}
Upvotes: 0
Views: 139
Reputation: 257711
The @ObservedObject
is a pattern of View, it has no sense outside, ie. in this case in model.
Here is a possible solution for provided code.
1) in model
final class OnboardingViewModel: ObservableObject {
var loader = Loader() // << just property
// ... other code
2) in view
struct ContentView: View {
@EnvironmentObject var onboardingViewModel: OnboardingViewModel
var body: some View {
InnerView(loader: onboardingViewModel.loader) // << pass from Env
}
struct InnerView: View {
@ObservedObject var loader: Loader
var body: some View {
ZStack {
if loader.isLoading { // this is where it is not updated
LottieView(named: .loading,
loop: loader.isLoading,
width: 220, height: 220)
}
}
}
}
}
Note: I don't see where you call onboardingViewModel.demoLogin()
, but I expect it is activate somewhere, because as I see it is the only function that activates Loader
.
Upvotes: 1