ViewModel异步功能完成后,如何从子视图中更新EnvironmentObject

时间:2020-08-12 21:26:36

标签: mvvm swiftui

在我的SwiftUI应用中,我有一个如下的入口点

@main
struct SomeApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            AppContainerView()
        }
    }
}
struct AppContainerView: View {
    @StateObject var appState = AppState()
    var body: some View {
        if appState.isLoggedIn && appState.hasSeenOnboarding {
            TabContainerView()
        } else {
            LandingView().environmentObject(appState)
        }
    }
}

我可以像这样更新isLoggedIn ...

class AppState: ObservableObject {
    var cancellables: [AnyCancellable] = []
    private let userService: UserServiceProtocol
    init(userService: UserServiceProtocol = UserService()) {
        self.userService = userService
        subscribeForAuthChanges()
    }
    
    func subscribeForAuthChanges() {
        userService.authChangeSubject.sink(receiveValue: { [weak self] auth, user in
            print(auth)
            if user != nil {
                self?.isLoggedIn = true
            }
        }).store(in: &cancellables)
    }
    
    @Published var isLoggedIn = false
    @Published var hasSeenOnboarding = false
}

但是关于hasSeenOnboarding,需要在LandingView子视图之一的viewModel中完成一些网络调用后,将其设置为true。我可以做这样的事情...

struct ChildView: View {
  @EnvironmentObject var appState: AppState
  @StateObject var viewModel = ChildViewModel()

  var body: some View {
    VStack {
      //...
    }.onReceive($viewModel.networkCallCompleted) { completed in
       self.appState.hasSeenOnboarding = completed
    }
  }
}

但这感觉不对...在使用MVVM时,这里是否有更好的选择从childView / viewModel更改appState?还是更好的方法?

1 个答案:

答案 0 :(得分:1)

一种可能的选择是将AppState传递到ChildViewModel并直接在视图模型中执行AppState更新。

struct ParentView: View {
  @EnvironmentObject var appState: AppState

  var body: some View {
    ChildView(viewModel: ChildViewModel(appState: appState))
  }
}
struct ChildView: View {
  @EnvironmentObject var appState: AppState
  @StateObject var viewModel: ChildViewModel

  var body: some View {
    ...
  }
}

注意

您可能希望查看依赖项注入,以使其更加简洁。这是一个可能的示例:Simple Dependency Injection using @propertyWrapper