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
- A user clicks Sign in with Apple button
- Update the router.currentPage property of @EnvironmentObject when a user logs in successfully.
- 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.