10

My setup is simple, and my issue is not very different from this one. However to better explain it I have posted it here:

NavController -> VC1 -> VC2

VC1 is root view controller of NavController. VC2 is accessible via Push segue from VC1.

I want to detect, within VC1, whether:

It appeared directly as root view controller (via Push) It appeared as a result of VC2 being popped

I read the docs which says following should tell me if later is true.

isMovingToParentViewController == NO 

However that is not the case, and above condition ALWAYS turns out to be TRUE. Which means that, (self.isMovingToParentViewController == NO) is always happening.

Here is my code:

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.navigationController.navigationBarHidden = YES;

    //pushed to stack
    if (self.isMovingToParentViewController == YES)
    {
        //First time
      }
    else
    //popped off
    {
        //via Pop from VC2
    }    
}

Same is the case for viewDidAppear, too.

For a matter of fact check, I put breakpoint at the start, and checked that all of the following are FALSE, in both cases:

([self isMovingFromParentViewController])
([self isMovingToParentViewController])
([self isBeingPresented])
([self isBeingDismissed])

What is happening? Is there anything I goofed up in my storyboard? Please help...

Community
  • 1
  • 1
Nirav Bhatt
  • 6,940
  • 5
  • 45
  • 89
  • 1
    Does it help if you add the expected call to `[super viewWillAppear:animated];` to the start of your `viewWillAppear:` method? – rmaddy Apr 24 '14 at 15:14
  • I did include that line at the very beginning of `viewWillAppear`, but to no result. – Nirav Bhatt Apr 24 '14 at 15:17
  • All four of those methods should return `NO` in `VC1` when `VC2` is popped. But I would expect `isMovingToParentViewController` to return `YES` the very 1st time that `VC1` is displayed. – rmaddy Apr 24 '14 at 15:20
  • What I've always used to do this in viewWillAppear is to use `[self.navigationController.viewControllers containsObject:self]` It will be false if self is being pushed, true if we're popping back to self. – David Berry Apr 24 '14 at 15:27
  • Some experimentation shows that isMovingToParentViewController is only true when a viewController is being pushed to a navigation stack. It's not set for the rootViewController. – David Berry Apr 24 '14 at 15:31

5 Answers5

14

Unfortunately, isMovingToParentViewController isn't true for the root view controller, so I usually handle this situation with a BOOL,

@implementation ViewController {
    BOOL isFirstAppearance;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    isFirstAppearance = YES;
}

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (isFirstAppearance) {
        NSLog(@"root view controller is moving to parent");
        isFirstAppearance = NO;
    }else{
        NSLog(@"root view controller, not moving to parent");
    }
}
rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • 1
    This fails with state restoration when a hierarchy is restored because the first time the root VCs view is loaded is when going back. – malhal May 29 '19 at 11:18
6

A simple solution is by adding a flag on viewWillDisappear setting it to YES if the VC1 has been disappeared. Else the view has never been disappeared so it is the first push (RootViewController of Navigation Controller).

Example Code

BOOL hasDisappeared;

-(void)viewWillAppear:(BOOL)animated
{
    if (hasDisappeared==YES) {
        //VC2 has been popped
    }
    else
    {
        //VC1 is the rootViewController
    }
}

-(void)viewWillDisappear:(BOOL)animated
{
    //Pushing to VC2
    hasDisappeared=YES;
}
E-Riddie
  • 14,660
  • 7
  • 52
  • 74
  • 1
    I was just typing a very similar answer. I've been doing this since long before the `isMovingToParentViewController` method was added. – rmaddy Apr 24 '14 at 15:36
  • This is the simplest way, another method I was going to write was @rdelmar for viewDidLoad, but I just came up with this idea. – E-Riddie Apr 24 '14 at 15:38
  • Can `UINavigationControllerDelegate` help? This approach is quite simple but doesn't necessarily address Push Pop thing. Surprising we have so many methods and none of them useful! – Nirav Bhatt Apr 24 '14 at 15:50
  • I quite don't get you @NiravBhatt, the idea here is that when the VC1 is disappeared, it has been pushed to VC2. in viewWillAppear when the hasDisappeared=YES, VC2 has been popped. – E-Riddie Apr 24 '14 at 15:53
  • What I meant is that this solution doesn't exactly address Push/Pop event in case of root view controller. In any case, this is inevitable and considering the timestamp I have marked @rdelmar's answer. +1 for your help. – Nirav Bhatt Apr 24 '14 at 18:44
  • I have updated the question, tell me where is the part that you don't understand? Is the same logic as @rdelmar, and considering timestamp, I am first but that doesn't matter, hope that you have fixed your problem. – E-Riddie Apr 25 '14 at 09:20
4

Since it appears that isMovingToParentViewController is only set when a viewController is being pushed to the navigation stack, and not set for the initial rootViewController, I'd suggest using the following:

 if([self.navigationController.viewControllers containsObject:self])
 {
     // being popped to self here
 }
 else
 {
     // being pushed here
 }
David Berry
  • 40,941
  • 12
  • 84
  • 95
  • But wouldn't the `if` be true when `self` is the root controller and it is being shown for the 1st time? – rmaddy Apr 24 '14 at 15:33
  • Looks like you're correct @rmaddy. Guess I've never used it for the rootViewController before... – David Berry Apr 24 '14 at 15:36
  • @rmaddy is right. `if([self.navigationController.viewControllers containsObject:self])` always turns out to be TRUE. – Nirav Bhatt Apr 24 '14 at 15:47
  • Looked back and I was actually using it to trigger completion blocks in `viewWillDisappear:` not `viewWillAppear:` – David Berry Apr 24 '14 at 16:10
0

You have to check isMovingFromParentViewController in VC2’s viewWillDissapear and call a delegate method implemented in VC1. I.e. VC2 is being removed from its parent nav controller because of being popped.

malhal
  • 26,330
  • 7
  • 115
  • 133
0

an alternative flag way ,

if your viewController doesn't support gesture popping,


     var onceDo = true

     override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if onceDo{
            // ...
            //  VC1 is the rootViewController
            onceDo = false
        }
        else{
            //VC2 has been popped
        }
    }
dengApro
  • 3,848
  • 2
  • 27
  • 41