ios appDelegate窗口setRootViewController崩溃

时间:2014-05-05 23:01:01

标签: ios objective-c ipad uinavigationcontroller uisplitviewcontroller

我有一个我正在研究的应用程序,这是普遍的。在iphone版本中,我使用标准的UINavigationController堆栈进行导航,一切都很好。但是,在ipad版本中,我使用的是UISplitViewContoller导航器,但登录屏幕只是标准的UIViewControllers。直到最近,当我不得不在细节方面改变导航时,这一点工作正常。基本上现在取决于主机中加载的内容,我必须在详细导航控制器中擦除堆栈并替换它的根。从那以后,有时当你点击退出时,每当会话超时并且用户被发送到登录屏幕时,应用程序崩溃:

* thread #1: tid = 0x140896, 0x0000000102143fcb libobjc.A.dylib`objc_msgSend + 11, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x0000000102143fcb libobjc.A.dylib`objc_msgSend + 11
frame #1: 0x000000010109ffb2 UIKit`-[UISplitViewController _calculateDelegateHiddenMasterOrientations] + 48
frame #2: 0x00000001010a284b UIKit`-[UISplitViewController hidesMasterViewInLandscape] + 42
frame #3: 0x000000010109fec7 UIKit`-[UISplitViewController _isMasterViewShownByDefault] + 75
frame #4: 0x000000010109fee7 UIKit`-[UISplitViewController _isMasterViewShown] + 23
frame #5: 0x00000001010a2e18 UIKit`-[UISplitViewController viewWillDisappear:] + 70
frame #6: 0x0000000100dd6e42 UIKit`-[UIViewController _setViewAppearState:isAnimating:] + 563
frame #7: 0x0000000100dd7ef8 UIKit`-[UIViewController viewWillMoveToWindow:] + 316
frame #8: 0x0000000100d30e00 UIKit`-[UIView(Hierarchy) _willMoveToWindow:] + 430
frame #9: 0x0000000100d2fd2a UIKit`__UIViewWillBeRemovedFromSuperview + 346
frame #10: 0x0000000100d2fb07 UIKit`-[UIView(Hierarchy) removeFromSuperview] + 67
frame #11: 0x0000000100d13f95 UIKit`-[UIWindow setRootViewController:] + 262
* frame #12: 0x0000000100047471 Callidus Enablement`__35+[CEInterfaceFunctions OpenLoginVC]_block_invoke(.block_descriptor=<unavailable>) + 609 at CEInterfaceFunctions.m:186
frame #13: 0x000000010336f851 libdispatch.dylib`_dispatch_call_block_and_release + 12
frame #14: 0x000000010338272d libdispatch.dylib`_dispatch_client_callout + 8
frame #15: 0x00000001033723fc libdispatch.dylib`_dispatch_main_queue_callback_4CF + 354
frame #16: 0x00000001024b6289 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
frame #17: 0x0000000102403854 CoreFoundation`__CFRunLoopRun + 1764
frame #18: 0x0000000102402d83 CoreFoundation`CFRunLoopRunSpecific + 467
frame #19: 0x00000001030fcf04 GraphicsServices`GSEventRunModal + 161
frame #20: 0x0000000100cdde33 UIKit`UIApplicationMain + 1010
frame #21: 0x000000010005f523 Callidus Enablement`main(argc=1, argv=0x00007fff5fbfec50) + 115 at main.m:16

我如何切换详细信息堆栈的示例:

if (![appDelegate.window.rootViewController isKindOfClass:[UISplitViewController class]]) {
    appDelegate.window.rootViewController = [[UIStoryboard storyboardWithName:@"Main_iPad" bundle:nil] instantiateViewControllerWithIdentifier:@"split"];
}
UISplitViewController *splitViewController = (UISplitViewController *)appDelegate.window.rootViewController;
NSArray* VCs = splitViewController.viewControllers;
UINavigationController* masterNav = (UINavigationController*)VCs[0];
UINavigationController* detailNav = (UINavigationController*)VCs[1];

[masterNav popToRootViewControllerAnimated:NO];

[detailNav setViewControllers:@[[masterNav.storyboard instantiateViewControllerWithIdentifier:@"recent"]] animated:NO];

登录屏幕加载代码示例:

dispatch_async(dispatch_get_main_queue(), ^{
    AppDelegate* appDelegate = [[UIApplication sharedApplication] delegate];
    UIStoryboard* sb;
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
        sb = [UIStoryboard storyboardWithName:@"Main_iPad" bundle:nil];
    } else {
        sb = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:nil] ;
    }
    NSLog(@"sb:%@ appd:%@ win:%@ root:%@",sb,appDelegate,appDelegate.window,appDelegate.window.rootViewController);

    UIViewController* vc =[sb instantiateViewControllerWithIdentifier:@"login"];
    NSLog(@"vc:%@",vc);
    appDelegate.window.rootViewController = vc;//Crash happens HERE
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
    }
    [appDelegate.window makeKeyAndVisible];
});

任何帮助都会很棒!

2 个答案:

答案 0 :(得分:2)

它可能与分割控制器上尚未完成的动画或转换有关。也许是一个警报视图?

无论如何,我建议在你未更改的rootController的模板上“登录”登录控制器,这样你就不必操作控制器,可以在登录控制器中设置动画。


例如:presentViewController:animated:completion:

答案 1 :(得分:0)

您的代码存在各种问题。首先,您应该在app delegate

的方法中设置窗口rootController
application:didFinishLaunchingWithOptions:

在应用程序启动的这个特殊时刻之外,您应该避免使用它。其次,考虑到你的第一段代码,你实际上在改变rootController是什么?不是你的路线:

  if (![appDelegate.window.rootViewController isKindOfClass:[UISplitViewController class]]) {

说你已经有一个?为什么要这个测试?

然后,这条线是没用的:

 [masterNav popToRootViewControllerAnimated:NO];

假设你没有在masterNav类的实例的initWithCoder:方法中做一些特别的事情(如果我们信任放在实例前面的强制转换,那么它是标准的UINavigationController,但是这可能只是隐藏故事板中的真相。)

现在,要真正回答您的问题,您需要指出“登录屏幕加载代码”的确切位置。在什么课上,叫哪里?你为什么要在dispatch_async(dispatch_get_main_queue(), ^{...区块内调用它?

通常,你应该在application:didFinishLaunchingWithOptions:方法内,无论如何都在主线程(==主队列)上调用。

最后一个问题:为什么要在两个不同的地方设置窗口根控制器?对于您尝试解决的问题,您的代码是人为复杂的(否则完全相关)。