AppDelegate, rootViewController и presentViewController
Я занимаюсь учебным пособием по интеграции в Facebook, я хочу показать свой MainViewViewController, если у пользователя есть действительный токен для текущего состояния, иначе я хочу показать LoginViewController.
MainViewAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
// To-do, show logged in view
} else {
// No, display the login page.
[self showLoginView];
}
return YES;
}
- (void)showLoginView
{
UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
LoginViewController* loginViewController = [mainstoryboard instantiateViewControllerWithIdentifier:@"LoginViewController"];
[self.window.rootViewController presentViewController:loginViewController animated:YES completion:NULL];
}
Ошибка консоли:
Warning: Attempt to present <LoginViewController: 0xb492fd0> on <MainViewViewController: 0xb1bd820> whose view is not in the window hierarchy!
Я не хочу использовать NavigationController.
Ответы
Ответ 1
У меня была такая же проблема. Основываясь на ответе на этот вопрос, я добавил [self.window makeKeyAndVisible]
непосредственно перед presentViewController:animated:completion:
и исправил его для меня.
В вашем случае showLoginView становится
- (void)showLoginView
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:@"LoginViewController"];
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:loginViewController animated:YES completion:NULL];
}
Ответ 2
Иногда представление модального контроллера просмотра из window.rootViewController может вызывать такое же предупреждение и не иметь никакого эффекта.
Пример такой иерархии диспетчеров представлений:
- [ MYUITableViewController] (представленным с помощью MYUIViewController)
- [ MYUIViewController] (rootViewController из UINavigationController ниже)
- [ UINavigationController] (root)
Теперь вызов
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:[UIViewController new] animated:YES completion:nil];
вызовет это точное предупреждение (проверено как на iOS6, так и на 7 Sim)
Решение:
Вместо использования rootViewController - используйте верхнюю часть, представленную им:
UIViewController *topRootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topRootViewController.presentedViewController)
{
topRootViewController = topRootViewController.presentedViewController;
}
[topRootViewController presentViewController:yourController animated:YES completion:nil];
- Иногда keyWindow может быть заменено окном с nil rootViewController (показывая UIAlertViews, UIActionSheets на iPhone и т.д.), в этом случае вы должны использовать свойство окна UIView.
Ответ 3
Ответ Степана Генералова был правильным для меня в Swift 3!!!
Конечно, с новым синтаксисом и т.д., Поэтому я скопирую его здесь:
let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "MainApp") as! ViewController
var topRootViewController: UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!
while((topRootViewController.presentedViewController) != nil){
topRootViewController = topRootViewController.presentedViewController!
}
topRootViewController.present(vc, animated: true, completion: nil)
"MainApp" - это мой главный идентификатор контроллера в этом случае.
Я знаю, что есть другие способы, но если вам нужно иметь разные схемы URL для открытия разных частей вашего приложения, вы должны обрабатывать его в AppDelegate, поэтому это прекрасно, потому что в
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {}
вы можете просто проверить, что url
как строка, а затем решить, выполняете ли вы вышеуказанный письменный код или, возможно, похожий код с другим идентификатором для другого контроллера представления (withIdentifier
)
Ответ 4
В Swift 3: -
let storyboard = UIStoryboard(name: "Login", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "LoginViewController")
window?.makeKeyAndVisible()
window?.rootViewController?.present(viewController, animated: true, completion: nil)