4

I've implemented a dropdown menu into my iOS app that calls functions to navigate between different storyboards. Each element in that menu calls the following function in the AppDelegate class with a different storyboard name:

(void)changeController:(NSString*)storyboardName
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:[NSBundle mainBundle]];

    //initialize the new view
    currentView = [storyboard instantiateInitialViewController];
    currentView.view.alpha = 0.0;
    currentView.view.frame = currentView.view.bounds;
    currentView.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    //the app crashes on this line with a Thread 1: signal SIGARBT message
    self.window.rootViewController = currentView;
    [self.window makeKeyAndVisible];

    //animate with a fade transition
    [UIView animateWithDuration:transitionDuration
                          delay:0.0
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{currentView.view.alpha = 1.0;}
                     completion:^(BOOL finished){}];
}

The problem is that the function that gets called crashes the app inconsistently. It works from some screens and not others. And even worse, it sometimes works on screens that it normally crashes on.

There are two error messages that get dumped to the console, and they are (I've added line breaks for readability):

Objective: {
 objective 0x15e4b3c0: <750:-1.64135e-05> + <750:8.34465e-08>
 *<orphaned without delegate (bug!):0x1703c790>{id: 188} + <750:4.17233e-08>
 *<orphaned without delegate (bug!):0x1703c980>{id: 192} + <750:-2.68221e-08>
 *UIView:0x170c6e40.Height{id: 1091}
}

and

uncaught exception: <NSISEngine: 0x15e0b380>{ Rows:
    UIWindow:0x15db3160.Height{id: 140} == 960 + 1*0x15dd03e0.marker{id: 144}
    UIWindow:0x15db3160.Width{id: 137} == 640 + 1*0x15dd03b0.marker{id: 141}
    UIWindow:0x15db3160.minX{id: 136} == 0 + 2*0x15dd0200.marker{id: 135} + -0.5*0x15dd03b0.marker{id: 141}
    UIWindow:0x15db3160.minY{id: 139} == 0 + 2*0x15dd0350.marker{id: 138} + -0.5*0x15dd03e0.marker{id: 144}
    objective{id: 1} == {
         objective 0x15e4b3c0: <750:-1.64135e-05> + <750:8.34465e-08>
         *<orphaned without delegate (bug!):0x1703c790>{id: 188} + <750:4.17233e-08>
         *<orphaned without delegate (bug!):0x1703c980>{id: 192} + <750:-2.68221e-08>
         *UIView:0x170c6e40.Height{id: 1091}}

     Constraints:
         <NSAutoresizingMaskLayoutConstraint:0x15dd03b0 h=--- v=--- H:[UIWindow:0x15db3160(320)]>       Marker:0x15dd03b0.marker{id: 141}
         <NSAutoresizingMaskLayoutConstraint:0x15dd03e0 h=--- v=--- V:[UIWindow:0x15db3160(480)]>       Marker:0x15dd03e0.marker{id: 144}
         <_UIWindowAnchoringConstraint:0x15dd0200 h=--- v=--- UIWindow:0x15db3160.midX == + 160>        Marker:0x15dd0200.marker{id: 135}
         <_UIWindowAnchoringConstraint:0x15dd0350 h=--- v=--- UIWindow:0x15db3160.midY == + 240>        Marker:0x15dd0350.marker{id: 138}

    Integralization Adjustments:
         (none)

    Statistics:
    4 rows. Variable counts:
            1 ->   2
            2 ->   2
}: internal error.  Cannot find an outgoing row head for incoming head UIView:0x170c6e40.Height{id: 1091}, which should never happen.

It's the last line that really confuses me, "internal error .... which should never happen."

I'm curious if anyone else has encountered this error, and how they tackled it.

  • Is this an issue with initializing the variable currentView, or perhaps something to do with the AppDelegate's window variable?

  • Is this really an issue with storyboard constraints? And if so, is there a limit to the number of constraints I can/should put on a single screen?


EDIT:

I figured out that the error was really only caused when navigating away from one particular storyboard. A constraint on the screen was throwing the error. So I added some code to the changeController: to programmatically remove the constraints from every subview and then remove every subview from the superview.

The problem was ultimately resolved when the constraints in the offending UIViewController were cleared and recreated.

Thanks for all your help and suggestions.

Kylaaa
  • 6,349
  • 2
  • 16
  • 27
  • I'll take two guesses. 1) Try commenting out the fade transition, and just set the `currentView.view.alpha` to 1 initially. My concern is that the previous view is deallocated as soon as you set the `rootViewController` and hence the transition doesn't work. 2) It's a multi-threading problem with a retain loop. Some subset of the old view hierarchy is being held in memory, and a background thread queues an update for the old view hierarchy after the `rootViewController` has been changed. Not sure how to track that down other than to do a code review of any multi-threading in your app. – user3386109 Jun 27 '14 at 20:37
  • I'm guessing that by the time you get that last error memory has been rather badly thrashed. – Hot Licks Jun 27 '14 at 21:07
  • The problem persists even after commenting out the fade transition, but I think you're onto something with the asynchronous deallocation of UIViews. I've tried programmatically removing all of the subviews and can reproduce the bug within the removal loop. But, the console log messages are not appearing in the order that I expected. I'll comment again if I make a breakthrough. – Kylaaa Jun 27 '14 at 21:09
  • Your comment in the code says "Thread 1" - is that a typo? This should all be happening on the main thread (Thread 0). – ChrisH Jun 27 '14 at 21:20
  • @ChrisH, I just double checked, and it is Thread 1. Even when all the animations have been commented out, the error always turns up on Thread 1. – Kylaaa Jun 27 '14 at 21:32
  • What is calling `changeController:` ? – ChrisH Jun 27 '14 at 21:33
  • I'm using a wrapper class around the KxMenu (https://github.com/kolyvan/kxmenu/) as my custom drop down menu. When a user taps on one of the menu items it fires off a function in the AppDelegate. That function is as follows : `- (void)loadLocationController:(id)sender { NSLog(@"Loading Location Controller"); [UIView animateWithDuration:transitionDuration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{currentView.view.alpha = 0.0;} completion:^(BOOL finished) { [self changeController:@"LocationsStoryboard"]; }]; }` Ugh, sorry about the formatting. – Kylaaa Jun 27 '14 at 21:42
  • My guess is whatever is firing the function isn't doing it on the main thread. Try wrapping the `animateWithDuration:completion:` method call in a dispatch_async on the main queue and see if that fixes it. – ChrisH Jun 27 '14 at 22:22
  • An interesting idea! But it seems that the error occurs when changeController: somehow gets called before loadLocationController:. This is highly peculiar because changeController: is only ever called within one of the load___Controller: functions. – Kylaaa Jun 27 '14 at 22:47
  • 1
    I also faced the same problem. During the segue navigation the app just crashes with the same log from the question. Started to play with the constraints of initial viewcontroller (deleting parts of the UI one by one) crash suddenly disappeared. Not sure why but constraints caused the crash. In my case the problem was with vertical alignment of two views one after another. First one used proportional width to super view and aspect ratio for height. The second view was placed just below the first one with vertical spacing constraint. After removing vertical spacing the crash gone. – vir us Oct 24 '14 at 19:09

0 Answers0