@Published property in @EnvironmentObject doesn't update the root view of my application

120 views Asked by At

I am trying to make a router object for my application using @EnvironmentObject. But the problem is the @Published property doesn't update the root view when the root view type is updated.

How it should work

  1. A user clicks Sign in with Apple button
  2. Update the router.currentPage property of @EnvironmentObject when a user logs in successfully.
  3. RootView get notified for updating router.currentPage and change the root view in accordance to the updated currentPage type.

Here are my codes below.

MainApp.swift

var body: some Scene {
  WindowGroup {              
    RootView().environmentObject(ViewRouter())
  }
}

ViewRouter.swift

Code Block 
enum Page {
 case signin
 case tasklist
}
final class ViewRouter: ObservableObject { 
    @Published var currentPage: Page = .signin
 }

RootView.swift

struct RootView: View {
 @EnvironmentObject var router: ViewRouter
 var body: some View {
  if router.currentPage == .signin {
   SigninView()
  } else {
   TaskListView()
  }
 }
}

SigninView.swift

struct SigninView: View {
 @EnvironmentObject var router: ViewRouter
 @State var signInHandler: SignInWithAppleCoordinator?
  
 var window: UIWindow? {
  guard let scene = UIApplication.shared.connectedScenes.first,
     let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate,
     let window = windowSceneDelegate.window else {
   return nil
  }
  return window
 }
  
 var body: some View {
  MyAppleIDButton().colorScheme(.light)
   .frame(width: 280, height: 38, alignment: .center)
   .onTapGesture {
    signInWithAppleButtonTapped()
   }
 }
  
 func signInWithAppleButtonTapped() {
  guard let _window = self.window else { return }
  signInHandler = SignInWithAppleCoordinator(window: _window)
  signInHandler?.signIn { (user) in
   router.currentPage = .tasklist
  }
 }
}

Update

I think I found an answer to this issue. I created a state isLoggedIn which is checking whether or not Sign in with Apple is done successfully.

@State var isLoggedIn: Bool = false

Then I added View Modifier onChange which is checking the value change of isLoggedIn above. Inside the onChange I assigned a new value to router.currentPage like below.

.onChange(of: isLoggedIn, perform: { isLoggedIn in
  if isLoggedIn {
    router.currentPage = .tasklist
      } else {
        router.currentPage = .signin
      }
  })

But I am still not sure of why it doesn't work in the closure of SigninWithApple button.

0

There are 0 answers