3

I have a button that triggers my view state. As I have now added a network call, I would like my view model to replace the @State with its @Publihed variable to perform the same changes.

How to use my @Published in the place of my @State variable?

So this is my SwiftUI view:

struct ContentView: View {

  @ObservedObject var viewModel = OnboardingViewModel()

  // This is the value I want to use as @Publisher
  @State var isLoggedIn = false

  var body: some View {
    ZStack {
      Button(action: {
        // Before my @State was here
        // self.isLoggedIn = true
        self.viewModel.login()
      }) {
        Text("Log in")
      }

      if isLoggedIn {
        TutorialView()
      }
    }
  }
}

And this is my model:

final class OnboardingViewModel: ObservableObject {

  @Published var isLoggedIn = false

  private var subscriptions = Set<AnyCancellable>()

  func demoLogin() {
    AuthRequest.shared.login()
      .sink(
        receiveCompletion: { print($0) },
        receiveValue: {
          // My credentials
          print("Login: \($0.login)\nToken: \($0.token)")
          DispatchQueue.main.async {
            // Once I am logged in, I want this
            // value to change my view.
            self.isLoggedIn = true } })
      .store(in: &subscriptions)
  }
}
Roland Lariotte
  • 2,606
  • 1
  • 16
  • 40

2 Answers2

1

Remove state and use view model member directly, as below

struct ContentView: View {

  @ObservedObject var viewModel = OnboardingViewModel()

  var body: some View {
    ZStack {
      Button(action: {
        self.viewModel.demoLogin()
      }) {
        Text("Log in")
      }

      if viewModel.isLoggedIn {    // << here !!
        TutorialView()
      }
    }
  }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • 1
    This is what I did at first, but it doesn't work. The @Published doesn't seem to send the true value to this "if statement". – Roland Lariotte May 10 '20 at 18:32
  • 1
    @RolandLariotte, what exactly does not work? Do you see console log on receive value from view model? – Asperi May 10 '20 at 18:35
  • What doesn't work is that I don't see my TutorialView() as it is still hidden by the "if viewModel.isLoggedIn { }". When I do the print as you suggest, the value is still false. When getting out the "self.isLoggedIn = true" out of the DispatchQueue, the value becomes true in the console but no change is being made to the view. – Roland Lariotte May 10 '20 at 18:43
  • 1
    @RolandLariotte, is this the only code or some simplified version? Is provided code the only place where `OnboardingViewModel()` created? – Asperi May 10 '20 at 19:01
  • Must know is that my Button is nested in another view. It is a simplified version as my views are very complex. – Roland Lariotte May 10 '20 at 19:01
  • 1
    @RolandLariotte, then check that *that another view" uses the same instance of OnboardingViewModel, because I'm now sure it does not. – Asperi May 10 '20 at 19:03
0

Hey Roland I think that what you are looking for is this:

$viewMode.isLoggedIn

Adding the $ before the var will ensure that SwiftUI is aware of its value changes.

struct ContentView: View {

  @ObservedObject var viewModel = OnboardingViewModel()

  var body: some View {
    ZStack {
      Button(action: {
        viewModel.login()
      }) {
        Text("Log in")
      }

      if $viewMode.isLoggedIn {
        TutorialView()
      }
    }
  }
}



class OnboardingViewModel: ObservableObject {

    @Published var isLoggedIn = false

    
    func login() {
       isLoggedIn = true
    }
}
Tiago Mendes
  • 4,572
  • 1
  • 29
  • 35