0

I have a view controller(VC1) embedded in a navigation controller(NAV1). In its viewWillAppear method, I make a call to modally present another view controller. In one case I need the new view controller(VC2) to be presented with animation, and in another case it should be presented without animation. VC2 is also embedded in its own navigation controller(NAV2).

All is fine when the animation flag is set to TRUE. When I set the flag to FALSE, couple of things go wrong: 1. I get the following warning in the console: Presenting view controllers on detached view controllers is discouraged 2. When I move back from VC2 after calling dismissViewControllerAnimated:FALSE completion:nil the viewWillAppear method of VC1 does not get called. It gets called if the animation flag is set to TRUE.

In VC1:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self performSelector:@selector(importStuff:)
                           withObject:nil];

}

-(void)importStuff
{
//instatntiate VC2
//instantiate NAV2

[Utility presentViewController:pNavController
            fromViewController:self
                      animated:FALSE
                    completion:nil];

// the above method calls the presentViewController:animated:completion: method
} 

IN VC2:

[Utility dismissViewController:self
                      animated:FALSE
                    completion:nil];

The above method calls the dismissViewControllerAnimated: method.

StudentX
  • 2,506
  • 5
  • 19
  • 28
  • 1
    Sounds like you are presenting the new view controller in the wrong place then? How about `viewDidAppear`? – trojanfoe Dec 18 '15 at 07:37
  • 1
    your already presented view is not completely presented and you are trying to present another controller, In case of without animation, time taken is far less and thus completing before your parent is presented – Syed Ali Salman Dec 18 '15 at 07:42
  • just try after adding this code in viewDidLoad. – Ronak Chaniyara Dec 18 '15 at 08:15
  • Adding the code in viewDidAppear did solve the problem. Adding it in viewDidLoad was not the solution for me. – StudentX Dec 18 '15 at 14:40

2 Answers2

3

Not a solution but a workaround:

You can easily postpone any UI operation to the very next event loop by using afterDelay:0:

[self performSelector:@selector(importStuff:)
           withObject:nil
           afterDelay:0];

This will give a chance to the current operation to complete.
Furthermore, a delay of 0.4 will match the OS. However, whatever delay you use (other than 0) is a kludge and not guaranteed to work under every situation, device and memory load, etc.

Instead, you should revisit your approach.


Change your design:

Do not run the risk of encountering this animation race in the first place. You have a couple of options, including:

  • Controlling the transition animation yourself and waiting for its completion prior pushing another view controller (using a completion signal or completion block)
  • Changing your methodology entirely to avoid this conundrum altogether
Community
  • 1
  • 1
SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
0
-(void)viewWillAppear:(BOOL)animated{

    [super viewWillAppear:animated];
    [self performSelector:@selector(importStuff) withObject:nil afterDelay:0.1];

   }

-(void)importStuff
{
    //instatntiate VC2
    //instantiate NAV2

    SecondViewController *viewMe=[self.storyboard instantiateViewControllerWithIdentifier:@"second"];
    [self.view.window.rootViewController presentViewController:viewMe animated:NO completion:nil];

    // the above method calls the presentViewController:animated:completion: method
}