【问题标题】:Applications are expected to have a root view controller at the end of application launch应用程序在应用程序启动结束时应该有一个根视图控制器
【发布时间】:2011-11-23 04:09:20
【问题描述】:

我在控制台中收到以下错误:

应用程序在应用程序启动结束时应该有一个根视图控制器

下面是我的application:didFinishLaunchWithOptions方法:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Set Background Color/Pattern
    self.window.backgroundColor = [UIColor blackColor];
    self.tabBarController.tabBar.backgroundColor = [UIColor clearColor];
    //self.window.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"testbg.png"]];

    // Set StatusBar Color
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent];

    // Add the tab bar controller's current view as a subview of the window
    self.window.rootViewController = self.tabBarController;
    [self.window makeKeyAndVisible];
    return YES;
}

在 Interface Builder 中,UITabBarController 的委托与 App Delegate 挂钩。

有人知道如何解决这个问题吗?

【问题讨论】:

  • 在你做分配之前做一个 self.tabBarController 的 NSLog。仅当控制器为 nil 时才会触发该消息。如果它为 nil,并且您已确保连接正确,请尝试在代码中实例化控制器。
  • 尝试评论窗口的初始化..检查这个答案stackoverflow.com/a/33958144/1293445

标签: ios objective-c


【解决方案1】:

使用自定义 ServiceLocator 处理 CoreData 时出现此类错误

let context: NSManagedObjectContext = try self.dependencies.resolve()

//solution
let context: NSManagedObjectContext? = try? self.dependencies.resolve()

【讨论】:

    【解决方案2】:

    这个 Swift 2 解决方案对我有用:

    在 AppDelegate 中插入下面的代码 -> didFinishLaunchingWithOptions

    self.window!.rootViewController = storyboard.instantiateViewControllerWithIdentifier("YourRootViewController") as? YourRootViewControllerClass
    

    【讨论】:

      【解决方案3】:

      我最近在使用 ios5 sdk 构建项目时遇到了同样的问题。 起初它正在正常构建和运行,但之后出现了错误。
      就我而言,解决方案相当简单。
      缺少的是,不知何故,我的应用程序目标的摘要选项卡中的 Main Interface 属性被删除了。所以我需要重新设置它。


      如果这不是重点,并且 tabBarController 仍然为 nil,您可以随时以编程方式创建窗口和根控制器。 作为后备,我将以下代码添加到我的项目中

      - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
      { 
          if (!window && !navigationController) {
              NSLog(@"Window and navigation controller not loaded from nib. Will be created programatically.");
              self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
              UIViewController *viewController1, *viewController2;
              viewController1 = [[[FirstViewController alloc] initWithNibName:@"FirstViewController_iPhone" bundle:nil] autorelease];
              viewController2 = [[[SecondViewController alloc] initWithNibName:@"SecondViewController_iPhone" bundle:nil] autorelease];
      
              self.tabBarController = [[[UITabBarController alloc] init] autorelease];
              self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
              self.window.rootViewController = self.tabBarController;
      
          }
          else {
              [window addSubview:[tabBarController view]];
          }
          [self.window makeKeyAndVisible];
          return YES;
      }
      

      这只有在 sho 的解决方案也被实施时才有效。

      【讨论】:

        【解决方案4】:

        setRootViewController:didFinishLaunchingWithOptions: 移动到 awakeFromNib: 在我的空项目中解决了这个问题。

        【讨论】:

        • awakeFromNib 究竟是什么? ://
        【解决方案5】:

        就我而言,关于实际窗口和didFinishLaunchingWithOptions: 方法的一切都很好。

        我的错误是我没有意识到 applicationDidBecomeActive: 在启动时运行,以及应用程序在后台运行后进入前台的时间。

        因此,在applicationDidBecomeActive: 中,我正在操作尚未完成所有设置的视图控制器(等待不同的线程响应,等等)。

        一旦我将此功能移到 applicationDidBecomeActive 之外,错误就消失了。

        【讨论】:

          【解决方案6】:

          如何为 iOS5 添加 RootViewController

          如果您的应用到现在还没有使用 RootViewController, 只需创建一个 ;) 通过点击 File > New > New File; 选择UIViewController subclass 将其命名为 RootViewController,取消选中 With XIB for user interface(假设您已经有一个) 并将此代码放入您的 AppDelegate :: didFinishLaunchingWithOptions

          rootViewController = [[RootViewController alloc] init];
          window.rootViewController = rootViewController;
          

          当然 - 你必须导入 RootViewController.h 并创建变量

          here is a nice article 关于 RootViewController 和 AppDelegate,

          【讨论】:

          • cupsofcocoa.com 文章链接已失效 - 知道某处是否有副本吗?
          • 这已移至 binpress.com,更新了答案中的链接
          • 这是一个很棒的链接。很好的阅读并解释了正在发生的事情。我刚刚使用一本旧书也遇到了这个问题(因为我想先学习 Objective-C),但是在最新的 XCode 7 上编写代码,它没有旧模板。
          【解决方案7】:

          我升级到 iOS9 并开始突然出现此错误。我能够修复它,但将以下代码添加到 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

          NSArray *windows = [[UIApplication sharedApplication] windows];
          for(UIWindow *window in windows) {
              if(window.rootViewController == nil){
                  UIViewController* vc = [[UIViewController alloc]initWithNibName:nil bundle:nil];
                  window.rootViewController = vc;
              }
          }
          

          【讨论】:

          • 我很想知道您的应用程序有多少个窗口,以及是否都有根视图控制器。谢谢
          • 注意:此答案是一种解决方法,并不能解决根本原因。见stackoverflow.com/a/33958144/1116061
          • 你是真正的英雄!
          【解决方案8】:

          如果您的应用将主 UIWindow 替换为 FingerTipWindow(以在投影仪上显示触摸)并且您已经有几年(几年)没有更新您的源代码,那么您的替换对象可能不包含 rootViewController 属性(参见 kgn 的 5/ 21/2013 mod GitHub)

          您可以在didFinishLaunchingWithOptions 中设置window.rootViewController 直到奶牛回家,但是您的窗口不会报告“在应用程序启动结束时”,并且会在运行时抛出异常。更新您的来源。

          【讨论】:

            【解决方案9】:

            为了补充 Mike Flynn 的回答,自从升级到 Xcode 7 并在 iOS 9 设备上运行我的应用程序后,我将此添加到我的 (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

            // Hide any window that isn't the main window
            NSArray *windows = [[UIApplication sharedApplication] windows];
            for (UIWindow *window in windows) {
                if (window != self.window) {
                    window.hidden = YES;
                }
            }
            

            【讨论】:

            • 我很想知道您的应用程序有多少个窗口,以及是否都有根视图控制器。谢谢
            【解决方案10】:

            没有一个答案能完全解决我的问题。

            我正在处理升级到 ARC 的旧 iOS4 项目,现在正在使用 Xcode 5 for iOS 7 进行处理

            我通读了所有这些并开始检查我的配置和代码。

            为我解决的问题是添加

            -(BOOL) application:(UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
            {
                // Maybe do something
                return YES;
            }
            

            除了拥有

            - (void)applicationDidFinishLaunching:(UIApplication *)application
            {
            }
            

            我没有

            -(BOOL) application:(UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
            

            在收到错误之前。

            【讨论】:

              【解决方案11】:

              以上方法都不适合我...在我的 appDelegate 上发现我的 init 方法有问题。如果您正在实现 init 方法,请确保您正确地执行它

              我有这个:

              - (id)init {
                  if (!self) {
                      self = [super init];
                      sharedInstance = self;
                  }
                  return sharedInstance;
              }
              

              并将其更改为:

              - (id)init {
                  if (!self) {
                      self = [super init];
                  }
                  sharedInstance = self;
                  return sharedInstance;
              }
              

              其中“sharedInstance”是指向我的 appDelegate 单例的指针

              【讨论】:

                【解决方案12】:

                我也遇到了这个错误,但没有列出的答案可以解决我的问题。 在我的情况下,日志显示是由于我在另一个子线程中分配应用程序根视图控制器的事实。

                -(BOOL) application:(UIApplication*) application didFinishLaunchingWithOptions:(NSDictionary*) launchOptions
                {
                    ...
                    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
                    dispatch_async(queue, ^{
                        ...
                        dispatch_async(dispatch_get_main_queue(), ^{
                            ...
                            [self updateTabBarTitles];
                            self.window.rootViewController = self.tabBarController;
                            ...
                        });
                    });
                
                    [self.window makeKeyAndVisible];
                    return YES;
                }
                

                通过将 rootViewController 分配移动到函数的末尾 - 就在调用 makeKeyAndVisible 之前: - 导致日志消息不再显示。

                {
                    ...
                    self.window.rootViewController = self.tabBarController;
                    [self.window makeKeyAndVisible];
                    return YES;
                }
                

                我希望这会有所帮助。

                【讨论】:

                  【解决方案13】:

                  使用 XCode 4.6.3 和 iOS 6.1 将我的 UI 替换为 Storyboard 后收到相同的错误

                  通过清除 AppDelegate 中的 didFinishLaucnhingWithOptions 中的所有代码解决了这个问题

                  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
                  {
                      return YES;
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    OrdoDei 给出了正确而有价值的答案。我添加这个答案只是为了给出一个didFinishLaunchingWithOptions 方法的示例,该方法使用他的答案以及考虑其他人关于导航控制器的 cmets。

                    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
                    {
                        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
                    
                        // Override point for customization after application launch.
                    
                        // Instantiate the main menu view controller (UITableView with menu items).
                        // Pass that view controller to the nav controller as the root of the nav stack.
                        // This nav stack drives our *entire* app.
                        UIViewController *viewController = [[XMMainMenuTableViewController alloc] init];
                        self.navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
                    
                        // Instantiate the app's window. Then get the nav controller's view into that window, and onto the screen.
                        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
                        // [self.window addSubview:self.navigationController.view];
                        // The disabled line above was replaced by line below. Fixed Apple's complaint in log: Application windows are expected to have a root view controller at the end of application launch
                        [self.window setRootViewController:self.navigationController];
                        self.window.backgroundColor = [UIColor whiteColor];
                        [self.window makeKeyAndVisible];
                        return YES;
                    }
                    

                    【讨论】:

                      【解决方案15】:

                      iOS 5.0 左右有一个细微的变化,需要你有一个根视图控制器。如果您的代码基于较旧的示例代码,例如GLES2Sample,则在这些代码示例中没有创建根视图控制器。

                      为了修复(例如 GLES2Sample),我在 applicationDidFinishLaunching 中创建了一个根视图控制器并将我的 glView 附加到它。

                      - (void) applicationDidFinishLaunching:(UIApplication *)application
                      {
                        // To make the 'Application windows are expected
                        // to have a root view controller
                        // at the end of application launch' warning go away,
                        // you should have a rootviewcontroller,
                        // but this app doesn't have one at all.
                        window.rootViewController = [[UIViewController alloc] init];  // MAKE ONE
                        window.rootViewController.view = glView; // MUST SET THIS UP OTHERWISE
                        // THE ROOTVIEWCONTROLLER SEEMS TO INTERCEPT TOUCH EVENTS
                      }
                      

                      这会使警告消失,并且不会真正影响您的应用。

                      【讨论】:

                        【解决方案16】:

                        我在升级到 Xcode 4.3 后就开始遇到同样的问题,并且仅在从头开始项目时(即创建空项目,然后创建 UIViewController,然后创建单独的 nib 文件)。

                        在放入所有我习惯的行并确保我有正确的连接后,我一直收到该错误,并且我试图通过视图控制器(设置为 rootController)加载的 nib 文件从未显示在模拟器。

                        我通过 Xcode 创建了一个单一的视图模板并将其与我的代码进行比较,最终发现了问题!

                        Xcode 4.3 似乎默认添加了方法 -(void)loadView;到视图控制器实现部分。仔细看了里面的cmets,问题就清楚了。如果以编程方式创建视图(我在解释),则注释指示覆盖 loadView 方法,否则如果使用笔尖,则不覆盖 loadView。这个方法里面没有其他东西,所以实际上我在使用 nib 文件时覆盖了这个方法(什么也不做),这给出了错误。

                        解决方案是要么从实现部分完全删除 loadView 方法,要么通过添加 [super loadView] 来调用父方法。

                        最好使用 NIB 文件删除它,因为添加任何其他代码实际上会覆盖它。

                        【讨论】:

                        • 这正是我的问题!我添加了一个 loadView 实现,但没有调用 super。做了一些其他的代码更改,不记得我做了什么。让我被困了 2 个小时,因为这种变化看起来如此无害。
                        【解决方案17】:

                        在“sho”答案之上,是正确的(UIApplicationMain 的第四个参数应该是主控制器的名称),我添加了一些 cmets。

                        我最近更改了我的应用程序的“模型”,不再使用 MainWindow.xib 以编程方式构建窗口。该应用程序使用了自动创建该 MainWindow 的旧模板。因为我想为 iPhone 5 支持不同的控制器视图 XIB,所以在创建 App Delegate 时以编程方式选择正确的 XIB 会更容易。我也从项目中删除了 MainWindow.xib。

                        问题是,我忘记在 UIApplication main 中填写第四个参数,并且我忘记在项目摘要的“主界面”中删除 MainWindow。

                        这导致了一个大问题:它在开发设备上呈现了无害的警告“应用程序应该...”,但是当它进入 App Store 时,它​​在消费者手机上崩溃了,因为 MainWindow 不再包含在捆绑包中!我不得不请求对错误修复进行加急审查。

                        另一个症状是有时会在更改设置并将应用程序置于前台时出现白色块,如空白 UIView。在 iPhone 5 中,很明显它是 320x480 块。也许缺少的 MainWindow 是在开发模式下使用旧大小创建的。当崩溃的第一批报告到达收件箱时,我刚刚发现了这个错误。

                        从 App Store 而非 XCode 安装应用程序显示该应用程序确实崩溃了,并且 MainWindow 问题在日志中显示出来,因此我可以看到它不是设备+IOS 版本的某种特殊组合。

                        【讨论】:

                          【解决方案18】:

                          我正在将旧的 EAGLView 示例项目迁移到 Xcode 4 中的新 GLKView 示例项目,但没有一个解决方案适合我。最后我意识到我正在尝试将主 GLKViewController 的 self.view 设置为指向 Interface Builder 中的嵌套 GLKView。

                          当我将 self.view 指向 Interface Builder 中的根 GLKView 时,我的应用程序能够启动而没有错误消息(因此请确保您的视图控制器的视图设置为根视图)。

                          附:如果您想让嵌套的 GLKView 工作,请在 ViewController.h 中创建一个新的成员变量(如 self.glkSubview),并将其连接拖到 Interface Builder 中的嵌套 GLKView 上。然后确保将 self.glkSubview 的委托拖到文件的所有者。如果您为 GLKView 关闭了 setNeedsDisplay,则必须在“- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect”中手动调用 [self.glkSubview display]。

                          【讨论】:

                            【解决方案19】:

                            以上建议都没有解决我的问题。我的是这样的:

                            添加:

                            window.rootViewController = navigationController;
                            

                            之后:

                            [window addSubview:navigationController.view];
                            

                            在我的 appdelegate 中

                            - (void)applicationDidFinishLaunching:(UIApplication *)application {
                            

                            【讨论】:

                              【解决方案20】:

                              如果您使用 MTStatusBarOverlay,则会收到此错误。

                              MTStatusBarOverlay 创建一个没有根控制器的附加窗口([[UIApplication sharedApplication] windows)。

                              这似乎不会导致问题。

                              【讨论】:

                              • 你确定吗?你测试过吗?
                              • 我确信它会创建一个窗口并且我确信它不会在我的应用程序中造成问题。
                              • 您可以为 MTStatusBarOverlay 设置一个虚拟 VC 来修复它。
                              • 这正是我的问题。我有一个类似的设置,带有一个为通知栏添加的窗口,一旦我注释掉错误就消失了!在这种情况下,它似乎是无害的。
                              【解决方案21】:

                              我在 Xcode 4.5.1 中针对 iOS 5.1 的 iPad 应用程序中遇到了这个问题。该应用程序使用 UITabBarController。我需要标签栏控制器中的一个新部分,所以我创建了一个新的视图控制器和 xib。将新的视图控制器添加到选项卡栏控制器后,我的屏幕控件都不再起作用,并且我得到了“预期有一个根视图控制器”日志。

                              不知何故,新 xib 中的顶级对象是 UIWindow 而不是 UIView。当我将一个 UIView 放到 XIB 中,让视图出口指向它,将所有子视图移动到新的 UIView 中,并删除 UIWindow 实例,问题就解决了。

                              【讨论】:

                                【解决方案22】:

                                在 AppDelegate 中替换

                                 [window addSubview:[someController view]];
                                

                                  [self.window setRootViewController:someController];
                                

                                【讨论】:

                                • 这摆脱了我的消息。它仍然没有显示后续窗口,但这可能是一个不同的问题。谢谢。
                                • 如果你使用 UINavigationController 你应该首先 [[UINavigationController] initWithRootViewController:tableViewController] 然后使用上面的代码 [self.window setRootViewController:self.navigationController] 来设置窗口的根视图控制器
                                • Cocos2d 有一条评论说“// AddSubView 在 iOS6 上不起作用”所以这为我修复了它,因为我使用的是 iOS 6。
                                • addSubview 行是 Xcode/iOS SDK 早期版本项目模板的一部分。如果该应用程序可以追溯到很久以前,即使您没有编写它,您也可能拥有它。
                                • 你好,我收到了这个错误:- *** 断言失败 -[UIApplication _runWithMainScene:transitionContext:completion:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/ UIKit-3505.16/UIApplication.m:3294 如何解决这个问题
                                【解决方案23】:
                                • 在 Nib 文件中选择“窗口”
                                • 在“属性检查器”中选中“启动时可见”

                                • 手动创建 nib 文件时会发生这种情况。
                                • 此修复适用于常规 nib 模式 - 不适用于情节提要模式

                                【讨论】:

                                • 我认为这只能在情节提要模式中找到。
                                • 不,这个项目是普通的笔尖模式。 This 是故事板模式的截图。 “在启动时可见”与“是初始视图控制器”。
                                • 如果手动创建的window nib文件,并且默认不勾选“启动时可见”会在应用启动后提示此消息,这解决了我的问题!
                                • 哦,谢谢!最后,解决这个烦人的警告。即使您有makeKeyAndVisible,它也不能解决问题。只有这解决了我的警告。谢谢!
                                • '这发生在常规 nib 模式 - 不是情节提要模式' 不太正确。我也面临与Storyboard 相同的问题
                                【解决方案24】:

                                尽管这些答案中的很多似乎都是有效的,但它们都没有为我解决问题。我正在尝试使用空的应用程序模板并尝试直接加载到 .xib 文件以了解缘故(如旧窗口模板)。 Apple 似乎留下了一条正在运行的 NSLog 消息。

                                我在 Xcode 4.3 上,似乎没有什么能摆脱这条消息,我想知道为什么。最后我决定看看 Xcode 4.5 (preview/iPhone 6.0 build) 中会发生什么,消息不再存在。继续前进。

                                【讨论】:

                                  【解决方案25】:

                                  我遇到了同样的问题,但我使用的是 storyboard

                                  将我的storyboard InitialViewController 分配给我窗口的rootViewController

                                  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
                                  ...
                                  UIStoryboard *stb = [UIStoryboard storyboardWithName:@"myStoryboard" bundle:nil];
                                  self.window.rootViewController = [stb instantiateInitialViewController];
                                  return YES;
                                  }
                                  

                                  这解决了问题。

                                  【讨论】:

                                    【解决方案26】:

                                    听起来self.tabBarController 正在返回niltabBarController 可能没有在 Interface Builder 中连接。在 Interface Builder 中将 tabBarControllerIBOutlet 设置为 tabBarController

                                    【讨论】:

                                      【解决方案27】:

                                      这发生在我身上。通过编辑 .plist 文件解决。 指定主 nib 文件的基本名称。(应为 MainWindow.xib)。 希望这会有所帮助。

                                      【讨论】:

                                      • 这对我有用!这适用于您在 Xcode 4.2 中创建一个空项目,其中没有 MainWindow 存在,这就是我们必须连接它的方式。
                                      • 当我们无意中从“Info.plist”文件中删除了“Main nib file base name”行时,问题就发生了。再次插入此行即可解决问题。
                                      • 您也可以在项目属性中进行设置。选择项目,你的目标,你可以在 Summary -> iPhone / iPad Deployment info 中编辑它。
                                      • 这实际上是我的问题,导致处理在 rootViewController 上两次调用 viewDidLoad 和 viewWillAppear 的多个问题。在我的情况下,删除这是解决方案
                                      【解决方案28】:

                                      确保您的应用程序委托中有此功能。

                                      - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:    (NSDictionary *)launchOptions {
                                         return YES;
                                      }
                                      

                                      确保 didFinishLaunchingWithOptions 返回 YES。如果您碰巧删除了 'return YES' 行,这将导致错误。此错误在情节提要用户中可能尤其常见。

                                      【讨论】:

                                      • 许多荣誉,这就是我想要的(带有故事板的空项目)
                                      • 这里也一样。谢谢。如果创建空应用程序,此方法将填充手动创建窗口。这应该更改为简单地返回 YES。谢谢
                                      【解决方案29】:

                                      我收到了同样的错误消息,因为我在

                                      中调用了警报
                                      - (void)applicationDidBecomeActive:(UIApplication *)application 
                                      

                                      而不是

                                      - (void)applicationWillEnterForeground:(UIApplication *)application
                                      

                                      【讨论】:

                                        【解决方案30】:

                                        我通过执行以下操作解决了这个问题(上述其他解决方案都没有帮助):

                                        从与“主界面”关联的下拉菜单中选择另一个条目,然后重新选择“主窗口”然后重建。

                                        【讨论】:

                                          猜你喜欢
                                          • 1970-01-01
                                          • 2012-04-08
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          相关资源
                                          最近更新 更多