更改了 rootViewController 但旧 rootViewController 的视图仍在视图层次结构中
Changed rootViewController but the view of old rootViewController is still in the View Hierarchy
我有一个基本情况,当用户通过身份验证后,我删除当前屏幕(登录屏幕)并将其更改为应用程序内的另一个屏幕。
为此,我使用以下代码:
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
print("Window's subviews before removed = \(appDelegate.window?.subviews)")
appDelegate.window?.subviews.forEach { [=10=].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)")
}
这是输出:
这是用户可以在设备屏幕上看到的内容 - 看起来很不错:
但是,在 Debug View Hierarchy 工具中却不行:
如您所见,旧 rootViewController 的视图仍然存在,在 UIWindow
内,但不是它的子视图 - 如输出所示。
这个行为看起来很奇怪,有没有人遇到过这个问题?
使用此代码。无需手动删除视图。
appDelegate.window?.rootViewController = newRootViewController
appDelegate.window?.makeKeyAndVisible()
原因:
我在使用 Google 登录 SDK 和 Facebook 登录 SDK 登录时尝试替换 rootViewController
时遇到了这个问题。
这些 SDK 有一个身份验证屏幕,如下所示:
通过使用 Debug View Hierarchy,我意识到当显示身份验证屏幕 (2) 时,应用程序将 rootViewController
更改为 UITransitionView
。并且当身份验证屏幕被关闭 (3) 时,它再次将 rootViewController
更改为呈现身份验证屏幕 (1) 之前的状态。
状态(1):在呈现认证画面之前,rootViewController
是LoginViewController
。
状态(2):呈现认证画面,rootViewController
改为UITransitionView
。
状态(3):退出认证画面后,rootViewController
又回到了LoginViewController
。
调试视图层次结构中的状态 (1) + (3):
调试视图层次结构中的状态 (2):
我把我的代码改成rootViewController
在相应SDK的每个委托方法中,当认证完成时调用。
Google 登录SDK:signIn:didSignInForUser:withError:
Facebook 登录 SDK:logInWithReadPermissions:fromViewController:handler:
这些方法在用户通过身份验证后立即调用,而不管身份验证屏幕是否被关闭。
这意味着,有时,当用户的身份验证过程完成得太快时,甚至在身份验证屏幕关闭并且 rootViewController
更改为 LoginViewController
之前,就会出现问题。这意味着,当用户已通过身份验证但 rootViewController
仍然是 UITransitionView
.
时,问题介于两种状态 (2) 和 (3) 之间
解决方法:
暂时的,在我找到更好的解决方案之前,我防止用户的身份验证过程发生得太快,这意味着我等待状态 (3) 在用户完成 delaying 0.25 秒后完成经过身份验证,然后更改 rootViewController
.
0.25 是足够的时间让一切正常工作,但太快了用户会失去耐心。
我有一个基本情况,当用户通过身份验证后,我删除当前屏幕(登录屏幕)并将其更改为应用程序内的另一个屏幕。
为此,我使用以下代码:
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
print("Window's subviews before removed = \(appDelegate.window?.subviews)")
appDelegate.window?.subviews.forEach { [=10=].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)")
}
这是输出:
这是用户可以在设备屏幕上看到的内容 - 看起来很不错:
但是,在 Debug View Hierarchy 工具中却不行:
如您所见,旧 rootViewController 的视图仍然存在,在 UIWindow
内,但不是它的子视图 - 如输出所示。
这个行为看起来很奇怪,有没有人遇到过这个问题?
使用此代码。无需手动删除视图。
appDelegate.window?.rootViewController = newRootViewController
appDelegate.window?.makeKeyAndVisible()
原因:
我在使用 Google 登录 SDK 和 Facebook 登录 SDK 登录时尝试替换 rootViewController
时遇到了这个问题。
这些 SDK 有一个身份验证屏幕,如下所示:
通过使用 Debug View Hierarchy,我意识到当显示身份验证屏幕 (2) 时,应用程序将 rootViewController
更改为 UITransitionView
。并且当身份验证屏幕被关闭 (3) 时,它再次将 rootViewController
更改为呈现身份验证屏幕 (1) 之前的状态。
状态(1):在呈现认证画面之前,rootViewController
是LoginViewController
。
状态(2):呈现认证画面,rootViewController
改为UITransitionView
。
状态(3):退出认证画面后,rootViewController
又回到了LoginViewController
。
调试视图层次结构中的状态 (1) + (3):
调试视图层次结构中的状态 (2):
我把我的代码改成rootViewController
在相应SDK的每个委托方法中,当认证完成时调用。
Google 登录SDK:signIn:didSignInForUser:withError:
Facebook 登录 SDK:logInWithReadPermissions:fromViewController:handler:
这些方法在用户通过身份验证后立即调用,而不管身份验证屏幕是否被关闭。
这意味着,有时,当用户的身份验证过程完成得太快时,甚至在身份验证屏幕关闭并且 rootViewController
更改为 LoginViewController
之前,就会出现问题。这意味着,当用户已通过身份验证但 rootViewController
仍然是 UITransitionView
.
解决方法:
暂时的,在我找到更好的解决方案之前,我防止用户的身份验证过程发生得太快,这意味着我等待状态 (3) 在用户完成 delaying 0.25 秒后完成经过身份验证,然后更改 rootViewController
.
0.25 是足够的时间让一切正常工作,但太快了用户会失去耐心。