为什么我的@ObservedObject在我的视图中不执行更改?

时间:2020-05-11 14:28:42

标签: swiftui combine observableobject

我有一个简单的Loader,当其@Publisher设置为true时,它会执行加载动画。发出网络请求时,此发布者在ViewModel上设置为true。我希望此值可以更改我的看法,但事实并非如此。所示的ContentView更为复杂,彼此之间有许多视图,但这是所有视图的根视图。 加载程序是一个Lottie视图,当手动将所有内容设置为true时,该视图都可以完美地工作。加载程序是一个独立的@ObservableObject,我想在其他许多ViewModel中使用它。

为什么从ViewModel进行设置后,我的@ObservedObject var loader的视图状态没有发生任何变化?

我的装载机:

final class Loader: ObservableObject {
  @Published var isLoading = false
}

触发加载程序的我的视图模型: (在控制台中,加载程序的值会相应更改)

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
    }
  }
}

这是我希望发生魔术的SwiftUI视图: (由于子视图和内部相互包含组件,因此要复杂得多)

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)
     }
    }
  }
}

1 个答案:

答案 0 :(得分:1)

@ObservedObject是一种视图模式,它在外部没有任何意义,即在这种情况下是模型。

这是提供的代码的可能解决方案。

1)在模型中

final class OnboardingViewModel: ObservableObject {
  var loader = Loader() // << just property

  // ... other code

2)在视图中

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)
            }
         }
     }
  }
}

注意:我看不到您在何处调用onboardingViewModel.demoLogin(),但我希望它在某个地方被激活,因为据我所知,它是激活Loader的唯一功能。