【问题标题】:AppDelegate, rootViewController and presentViewControllerAppDelegate、rootViewController 和 presentViewController
【发布时间】:2012-11-05 23:32:01
【问题描述】:

我正在做 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。

【问题讨论】:

    标签: objective-c xcode facebook ios6 appdelegate


    【解决方案1】:

    我有同样的问题。根据对this question 的回答,我在presentViewController:animated:completion: 之前添加了[self.window makeKeyAndVisible],这为我解决了问题。

    在你的情况下, 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 呈现模态视图控制器可能会产生相同的警告并且没有效果。 这种视图控制器层次结构的示例:

    1. [MYUITableViewController](由 MYUIViewController 模态呈现)
    2. [MYUIViewController](下面UINavigationController的rootViewController)
    3. [UINavigationController](根)

    现在打电话

    [[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 的窗口(在 iPhone 上显示 UIAlertViews、UIActionSheets 等),在这种情况下,您应该使用 UIView 的 window 属性。

    【讨论】:

    • 我收到“对 的开始/结束外观转换的不平衡调用”
    • 各位,请帮忙,我有同样的问题,但不知道 Swift 版本会是什么?我这样做: var sharedApplicationVC : UIViewController! = self.window?.rootViewController while var vvc = sharedApplicationVC.presentedViewController{ sharedApplicationVC = vvc } sharedApplicationVC.presentViewController(closeableVC, animated: true, completion: nil) ,但它给了我内存泄漏问题: 可能也很有帮助。致命错误:在展开可选值时意外发现 nil
    • 如果屏幕上显示了 uialertcontroller 并且想要呈现另一个 viewcontroller 是否有效?
    • 谢谢! :) 拯救了我的一天 :)
    • 是的!我已经尝试了所有,但没有任何效果。这对我来说是正确的答案。拯救我的一天!谢谢。
    【解决方案3】:

    Stepan Generalov's answerSwift 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)

    【讨论】:

    • 为什么要使用一段时间而不是简单的 If?,If 更适合我
    【解决方案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)
    

    【讨论】:

      【解决方案5】:

      以防万一,当您不使用情节提要时。 首先,您需要创建 YourViewController。 转到文件 -> 新建 -> 文件...(或快捷方式 - 命令 + N)

      之后,选择 Cocoa Touch Class。单击下一步,或输入

      为您的 viewController 输入名称,然后单击下一步

      #import "AppDelegate.h"
      #import "YourViewController.h"
      
      @interface AppDelegate ()
      
      @end
      
      @implementaion AppDelegate
      
      - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      
      // Init window
      self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
      [self.window makeKeyAndVisible];
      
      // Init YourViewController
      YourViewController *viewController = [[YourViewController alloc] init];
      
      // Init YourNavigationController
      UINavigationController *navigationContoller = [[UINavigationController alloc] initWithRootViewController: viewController];
      
      // Set rootViewController
      self.window.rootViewController = navigationContoller;
      
      return YES;
      
      }
      
      @end
      

      Swift 3/4 示例

      import UIKit
      
      @UIApplicationMain
      
      class AppDelegate: UIResponder, UIApplicationDelegate {
      
      var window: UIWindow?
      
      func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
      
      //1-st step
      window = UIWindow(frame: UIScreen.main.bounds)
      window?.makeKeyAndVisible()
      
      //2-nd - create a window root controller, and create a layout
      let layout = UICollectionViewFlowLayout()
      window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
      
      return true
      

      }

      【讨论】:

        【解决方案6】:

        你可以在 Objective-C 中像这样从 root 启动一个新的 viewController

        UIViewController *presenter = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;
        
        [presenter presentViewController:yourViewController animated:YES completion:nil];
        

        别忘了添加这个:

        #import "AppDelegate.h"
        

        【讨论】:

        • 这将不起作用,除非 rootViewController 位于窗口层次结构中,但情况并非总是如此。尝试此操作时,我的应用收到警告。
        • @Brainware 可以在 appDelegates didFinishLaunchingWithOptions 函数中设置根视图控制器,例如: UIViewController *mainVC = [[MainVC alloc] initWithNibName:@"MainXB" bundle:nil]; [自我 setRootViewController:mainVC];或者你可以为你的 rootViewController 定义一个引用对象,并在不同的场景中改变它的值。
        • 另外,检查@Stepan-Generalov 解决方案。我认为它完全没问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多