Search code examples
iosobjective-cuiviewcontrollerfreezepresentmodalviewcontroller

UIViewController.presentModalViewController hangs indefinitely


I have 3 view controllers, VC1, VC2, and VC3, that are instantiated when the app starts. I want to present them modally in a loop, like this:

VC1 -> VC2 -> VC3 -> VC1

On each view controller, I'm presenting the next view controller like this:

[self presentModalViewController:nextViewController animated:TRUE];

The issue is when I execute that line from VC3, for presenting again the first view controller VC1, the app hangs and becomes completely unresponsive. As soon as that line is executed, I can see on Xcode CPU usage jumping from 0% to 99% and memory from 20MB to 1GB. I cannot even pause execution using the debugger, I can only quit the process. No errors on the console either.

My project doesn't have anything else, it's just these 3 view controllers, each with a button to present the next view controller in the loop.
Is this navigation flow not supported by the system or am I doing something wrong?

I tried doing the same thing using segues on the storyboard, and that works fine. But I need to understand why it doesn't work using UIViewController.presentModalViewController.

This is basically the code for each view controller:

#import "VC2.h"

@implementation VC2

- (IBAction)onNextButtonClicked:(id)sender {
    [self presentModalViewController:_nextViewController animated:TRUE];
}

@end

Solution

  • Your post is lacking some details -- however...

    I'm assuming you have your Storyboard / Segues setup like this:

    enter image description here

    That "works" -- well, it doesn't crash (right away) -- because each button is presenting a new instance of the next view controller.

    If you cycle through your 3 "present" segues a couple times, then go into Debug View Hierarchy, it will look something like this:

    enter image description here

    When you try to do this via code, you stated:

    "VC1, VC2, and VC3, that are instantiated when the app starts"

    So, let's say you have _vc1, _vc2 and _vc3, and you present _vc1.

    _vc1 then presents _vc2, which presents _vc3, which then tries to present _vc1. But, that instance of _vc1 is already in the view hierarchy, presenting _vc2 presenting _vc3 ... and you end up with (effectively) an infinite loop.

    A "carousel of presents" is a bit of an unusual interface... but, if that's what your goal is, you'll need to take another approach.

    One option would be to present a single view controller, which would instantiate and load the 3 VCs as child view controllers.

    Each child's view would be overlaid. When you want to go from VC1 to VC2, you can simulate the presentation by:

    • align VC2's view's Top to "main" view's bottom
    • bring VC2's view to the front
    • animate VC2's view up to the Top

    If you're interested, I posted a quick example of that approach here: https://github.com/DonMag/PresentCarousel