Изменен rootViewController, но представление старого rootViewController все еще находится в иерархии представлений. - PullRequest
0 голосов
/ 11 мая 2018

У меня есть базовая ситуация, когда пользователь прошел аутентификацию, я удаляю и изменяю текущий экран (экран входа в систему) на другой экран внутри приложения.

Для этого я использую этот код:

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)")
}

Это вывод:

enter image description here

Это то, что пользователь может видеть на экране устройства - выглядит очень хорошо: enter image description here

Однако в инструменте «Иерархия представлений отладки» это не так:

enter image description here

Как вы можете видеть, представление старого rootViewController все еще там, внутри UIWindow, но не его подпредставления - как указано в выводе.

Такое поведение кажется странным, кто-нибудь еще сталкивался с этой проблемой?

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Причина:

У меня возникает эта проблема, когда я пытаюсь заменить rootViewController при входе в систему с помощью Google Sign-In SDK и Facebook Login SDK.

Эти SDK имеют экран аутентификации , подобный этому:

enter image description here

Используя иерархию просмотра отладки, я понял, когда был представлен экран аутентификации (2), приложение изменило rootViewController на UITransitionView. И когда экран аутентификации закрывается (3), он еще раз переключил rootViewController в состояние перед представлением экрана аутентификации (1).

Состояние (1): перед отображением экрана аутентификации rootViewController равен LoginViewController.

Состояние (2): при отображении экрана аутентификации rootViewController изменено на UITransitionView.

Состояние (3): после закрытия экрана аутентификации rootViewController вернулось к LoginViewController.

Состояния (1) + (3) в иерархии просмотра отладки: enter image description here

Состояние (2) в иерархии представлений отладки: enter image description here

Я поместил свой код для изменения rootViewController в каждом методе делегата соответствующих SDK, который вызывается при завершении аутентификации.

Google Sign-In SDK: signIn:didSignInForUser:withError:

Facebook Login SDK: logInWithReadPermissions:fromViewController:handler:

Эти методы вызываются сразу после того, как пользователь прошел аутентификацию, независимо от того, закрывается экран аутентификации или нет.

Это означает, что иногда проблема возникает, когда процесс аутентификации пользователя завершается слишком быстро, даже до того, как экран аутентификации закрывается и rootViewController изменяется на LoginViewController. Это означает, что проблема заключается в двух состояниях (2) и (3), когда пользователь прошел аутентификацию, но rootViewController по-прежнему UITransitionView.

Решение:

Временно, прежде чем я смогу найти лучшее решение, я не позволяю процессу аутентификации пользователя произойти слишком быстро, это означает, что я жду, пока состояние (3) завершится, к задержке 0,25 секунды после того, как пользователь аутентифицируемый и затем изменяющий rootViewController.

0,25 - достаточно времени, чтобы все работало, и слишком быстро, чтобы пользователь терял терпение.

0 голосов
/ 11 мая 2018

используйте этот код. нет необходимости удалять виды вручную.

appDelegate.window?.rootViewController = newRootViewController
appDelegate.window?.makeKeyAndVisible()
...