I have a basic situation, when the user has been authenticated, I remove and change the current screen (the login screen) to another screen inside the app.
To do this, I use this code:
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
print("Window's subviews before removed = \(appDelegate.window?.subviews)")
appDelegate.window?.subviews.forEach { $0.removeFromSuperview() }
print("Window's subviews after removed = \(appDelegate.window?.subviews)")
appDelegate.window?.rootViewController?.view?.removeFromSuperview()
appDelegate.window?.rootViewController?.removeFromParentViewController()
appDelegate.window?.rootViewController = newRootViewController
print("Window's subviews after changed = \(appDelegate.window?.subviews)")
}
This is the output:
This is what the user can see on the device screen - looks very OK:
However, it isn't ok in the Debug View Hierarchy tool:
As you can see, the view of old rootViewController is still there, inside UIWindow
but not a subview of it - as the output has indicated.
This behavior seems strange, has anyone experienced this problem yet?
I have this problem when I try to replace rootViewController
while logged in using the Google Sign-In SDK and Facebook Login SDK.
These SDKs have an authentication screen like this one:
By using the Debug View Hierarchy, I realized when the authentication screen was presented (2), the app changed the rootViewController
to a UITransitionView
. And when the authentication screen is dismissed (3), it changed the rootViewController
once more to the state before presenting the authentication screen (1).
State (1): Before presenting the authentication screen, rootViewController
is LoginViewController
.
State (2): Presenting the authentication screen, rootViewController
changed to UITransitionView
.
State (3): After dismissed the authentication screen, rootViewController
has returned to LoginViewController
.
States (1) + (3) in Debug View Hierarchy:
State (2) in Debug View Hierarchy:
I put my code to change the rootViewController
in the each delegate method of corresponding SDKs that is called when authentication is completed.
Google Sign-In SDK: signIn:didSignInForUser:withError:
Facebook Login SDK: logInWithReadPermissions:fromViewController:handler:
These methods are called immediately after the user has authenticated without regard to the authentication screen is dismissed or not.
It means, sometimes, the problem occurs when the user's authentication process is completed too quickly, even before the authentication screen is dismiss and the rootViewController
changes to LoginViewController
. It means, the problem is in between two states (2) and (3), when the user has authenticated but rootViewController
is still UITransitionView
.
Temporary, before I can find a better solution, I prevent the user's authentication process from happening too quickly, it means that I wait for state (3) to finish by delaying 0.25 seconds after the user had authenticated and then changing rootViewController
.
0.25 is enough time for everything to work and too fast for the user to lose patience.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With