Domanda

I have an app I'm working on that that's universal. In the iphone version I use a standard UINavigationController stack for navigation and all is well with the world. However, in the ipad version I'm using a UISplitViewContoller nav for everything, but the login screens which are just standard UIViewControllers. And that was working fine until recently when I had to change up the navigation a bit on the detail side. Basically now depending on what's loaded in the master I have to wipe the stack on in the detail nav controller and replace the root of it. Since then sometimes when you hit logout and everytime the session times out and the user is sent to the the login screen the app crashes with:

* 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

Example of how I'm switching the detail stack:

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];

Example of the login screen loading code:

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];
});

Any help would be great!

È stato utile?

Soluzione

It may have something to do with an animation or transition not yet finished on the split controller. Maybe an alert view?

Anyway I would suggest presenting the login controller modally "on top" of your unchanged rootController so you don't have to juggle controllers and can animate in/out the login controller.


Eg.: presentViewController:animated:completion:

Altri suggerimenti

There are various issues with your code. First and foremost, you should set the window rootController inside the method of the app delegate

application:didFinishLaunchingWithOptions:

You should avoid playing with it outside this peculiar moment of app launch. Second, considering your first piece of code, what are you actually changing the rootController? Isn't your line:

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

saying that you have already one? Why this test?

Then, this line is useless:

 [masterNav popToRootViewControllerAnimated:NO];

assuming you don't do something special in the initWithCoder: method of the instance of the masterNav class (if we trust the cast put in front of the instance, it is a standard UINavigationController, but this might just hide the truth set inside the storyboard).

Now, to really answer your question, you need to indicate where exactly is located your "login screen loading code". In what class, and called where? And why are you calling this inside a dispatch_async(dispatch_get_main_queue(), ^{... block?

Normally, you should be inside the application:didFinishLaunchingWithOptions: method, which is called on the main thread (== main queue) anyway.

Last question: why are you setting the window root controller in two different places??? Your code is artificially complicated for the problem you try to solve (which is perfectly relevant otherwise).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top