我有一个基本情况,当用户通过身份验证后,我删除当前屏幕(登录屏幕)并将其更改为应用程序内的另一个屏幕。
为此,我使用以下代码:
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)")
}
这是输出:
但是,在 Debug View Hierarchy 工具中却不行:
如您所见,旧 rootViewController 的 View 仍然存在于 UIWindow
中,但不是它的 subview - 正如输出所示。
这个行为看起来很奇怪,有没有人遇到过这个问题?
最佳答案
原因:
我在使用 Google 登录 SDK 和 Facebook 登录 SDK 登录时尝试替换 rootViewController
时遇到了这个问题。
这些 SDK 有一个像这样的身份验证屏幕:
通过使用 Debug View Hierarchy,我意识到当显示身份验证屏幕 (2) 时,应用将 rootViewController
更改为 UITransitionView
。当身份验证屏幕消失 (3) 时,它再次将 rootViewController
更改为显示身份验证屏幕 (1) 之前的状态。
状态(1):在呈现身份验证屏幕之前,rootViewController
是LoginViewController
。
状态(2):呈现认证画面,rootViewController
变为UITransitionView
。
状态(3):关闭身份验证屏幕后,rootViewController
已返回到 LoginViewController
。
我将更改rootViewController
的代码放在相应SDK的每个委托(delegate)方法中,当身份验证完成时调用。
Google 登录 SDK:signIn:didSignInForUser:withError:
Facebook 登录 SDK:logInWithReadPermissions:fromViewController:handler:
这些方法在用户通过身份验证后立即调用,而不管身份验证屏幕是否被关闭。
这意味着,有时,当用户的身份验证过程完成得太快时,甚至在身份验证屏幕关闭并且 rootViewController
更改为 LoginViewController
之前,就会出现问题。这意味着,当用户已通过身份验证但 rootViewController
仍然是 UITransitionView
时,问题出现在两种状态 (2) 和 (3) 之间。
解决方案:
暂时,在我找到更好的解决方案之前,我防止用户的身份验证过程发生得太快,这意味着我等待状态 (3) 在 delaying 之前完成用户通过身份验证并更改 rootViewController
后 0.25 秒。
0.25 的时间足以让一切正常工作,但太快了用户会失去耐心。
关于ios - 更改了 rootViewController 但旧 rootViewController 的 View 仍在 View 层次结构中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50289680/