Подтвердить что ты не робот

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.

4b9b3361

Ответ 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)