title: SwiftUI access global state from ViewModel
body: <p>I am experimenting with SwiftUI and having a hard time figuring out the proper architecture for my app.</p>
  
  <p>What I am trying to achieve is simple. I want to have an initial screen that either show a sign up screen or the home screen for a given user depending on current authentication state. I cannot figure out how to make the initial screen pick up changes from the sign up screen once authentication has taken place. Here's some relevant code:</p>
  
  <pre class="lang-swift prettyprint-override"><code>struct InitialView: View {
      @EnvironmentObject var viewModel: InitialViewModel
  
      var body: some View {
          VStack {
              if viewModel.auth.identity != nil {
                  NewHomeView()
              } else {
                  SignInView()
              }
          }
      }
  }
  </code></pre>
  
  <p>In the sign in view, I have a usual sign in form and when the user presses the sign in button, I want to send a login request to the backend and remember the resulting token.</p>
  
  <pre class="lang-swift prettyprint-override"><code>
  class SignInViewModel: ObservableObject {
      private let auth: AuthStore
      private let signInApi: SignInApi
      private var cancellableSet: Set&lt;AnyCancellable&gt;
  
      // Input
      @Published var name: String = ""
      @Published var password: String = ""
      @Published var showSignUp: Bool = false
  
      // Output
      @Published var authSuccess: Bool = false
  
      init(auth: AuthStore, signInApi: SignInApi) {
          self.auth = auth
          self.signInApi = signInApi
          self.cancellableSet = Set&lt;AnyCancellable&gt;()
      }
  
      func signIn() {
          signInApi.signIn(email: name, password: password).sink(receiveCompletion: { _ in }) { response in
              self.auth.identity = Identity(
                  person: Person(id: 1, name: "user", sex: nil, birthday: nil),
                  token: response.token
              )
              self.authSuccess = true
          }.store(in: &amp;cancellableSet)
      }
  }
  </code></pre>
  
  <p>HOWEVER, this does not work. Even after clicking the sign in button, the initial view is not updated. Note that I am passing the same AuthStore to both view models.</p>
  
  <pre class="lang-swift prettyprint-override"><code>  let auth = AuthStore()
  
          // Create the SwiftUI view that provides the window contents.
          let contentView = InitialView()
              .environmentObject(InitialViewModel(auth: auth))
              .environmentObject(SignInViewModel(auth: auth, signInApi: SignInApi()))
  
  </code></pre>
  
  <p>where AuthStore is defined as</p>
  
  <pre><code>
  class AuthStore: ObservableObject {
      @Published var identity: Identity? = nil
  }
  </code></pre>
  
  <p>Ideally, I'd love to be able to 1) have each view be paired with its own VM 2) have each VM access global state via @EnvironmentObject. However, it seems that @EnvironmentObject is restricted to views only? If so, how do I access the global auth state from within each VM that requires it? </p>