Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if view controller is being popped of from the navigation controller?

I currently need to implement some code when the top view controller is being popped off from my navigation controller. Is there a way to detect when the view controller is being popped off the navigation controller stack?

As much as possible I want to stay away from using viewWillDisappear or viewDidDisappear because I'm using a splitview in my project, and selecting a different row in the master view will also trigger the viewWillDisappear/viewDidDisappear methods.

like image 559
aresz Avatar asked Feb 20 '14 17:02

aresz


People also ask

How do I know if my view controller is root view controller?

The root view controller is simply the view controller that sits at the bottom of the navigation stack. You can access the navigation controller's array of view controllers through its viewControllers property. To access the root view controller, we ask for the first item of the array of view controllers.

Can a view controller dismiss itself?

The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, UIKit asks the presenting view controller to handle the dismissal.

How do I add a view controller to my navigation controller?

Step 1: Embed root view controller inside a navigation controller. In your storyboard, select the initial view controller in your hierarchy. With this view controller selected, choose the menu item Editor -> Embed In -> Navigation Controller .

What is a navigation view controller?

Introduction to Navigation Controllers. A UINavigationController is a view controller subclass that makes navigation between multiple view controllers easier. In addition to easier navigation, a navigation controller also has a lot of built-in functionality that we'll explore in this section.


2 Answers

You can detect whether a view is being popped using the isMovingFromParentViewController property for a view controller as shown below:

- (void)viewWillDisappear:(BOOL)animated {     [super viewWillDisappear:animated];     if ([self isMovingFromParentViewController])     {         NSLog(@"View controller was popped");     }     else     {         NSLog(@"New view controller was pushed");     } } 

isMovingFromParentViewController

Returns a Boolean value that indicates that the view controller is in the process of being removed from its parent.

like image 173
Nishant Avatar answered Oct 14 '22 09:10

Nishant


UPDATE 2015-04-30

Based on phatmann's feedback (first comment below), I was curious if something had changed since I answer this question over a year ago. I put together a simple, example app, and have some results that are interesting.

Option 1, example

https://github.com/greymouser/TestNVC

I don't have the ability to easily test pre-8.x, so I'm not sure if something has changed since then. However, the behavior I originally described does still happen. However, thanks to puting together the test app, I did notice an oddity I didn't before.

If I just rely on {will,did}MoveToParentViewController, I noticed a spurious didMoveToParentViewController: call when pushing the first non-rootVC, on the rootVC, with parent != nil (implying it is added, not being removed). I didn't encounter this around the time of my original answer, as I usually have "permanent" rootVC's on my NVC's, and hadn't implemented the callbacks there. See the example app with logging set to LOG_WILL_DID_MTPVC (in ViewController.m). This is an -- edited for space -- snapshot of what I saw:

TestNVC[] -[vc(rootVC) willMoveToParentViewController [entering] TestNVC[] -[vc(rootVC) didMoveToParentViewController [entering] TestNVC[] -[vc(1) willMoveToParentViewController [entering] TestNVC[] -[vc(rootVC) didMoveToParentViewController [entering]  # <-- this is odd TestNVC[] -[vc(1) didMoveToParentViewController [entering] ... 

My original answer suggested using {will,did}MoveToParentViewController alone, as it was a "one stop shop" to handle this behavior. However, now that I've seen the spurious call to the rootVC, I suggest a mix of {will,did}MoveToParentViewController as well as the standard UINavigationControllerDelegate callbacks. For this behavior in the example app, set logging to LOG_WILL_DID_MTPVC_LEAVING_AND_NVC_WILL_DID_SHOW_VC. Now we see the following:

TestNVC[] -[nvcD willShowViewController]: rootVC TestNVC[] -[nvcD didShowViewController]: rootVC TestNVC[] -[nvcD willShowViewController]: 1 TestNVC[] -[nvcD didShowViewController]: 1 TestNVC[] -[nvcD willShowViewController]: 2 TestNVC[] -[nvcD didShowViewController]: 2 TestNVC[] -[vc(2) willMoveToParentViewController [leaving] TestNVC[] -[nvcD willShowViewController]: 1 TestNVC[] -[vc(2) didMoveToParentViewController [leaving] TestNVC[] -[nvcD didShowViewController]: 1 TestNVC[] -[vc(1) willMoveToParentViewController [leaving] TestNVC[] -[nvcD willShowViewController]: rootVC TestNVC[] -[vc(1) didMoveToParentViewController [leaving] TestNVC[] -[nvcD didShowViewController]: rootVC 

... and this makes much more sense now.

Option 2

Another option I didn't explore is using your NVC sublcass, overriding - pushViewController:animated: and - popViewControllerAnimated:, and applying whatever behaviors you want to the VC being pushed, or the VC that was returned from the pop. (Make sure to remember to call super in your overrides if you attempt this.)

Update summary

So, thanks to phatmann for the chance to readdress this. I think my answer is more correct now. However, I'm not so sure that it was ever "fully non-truthy". ;-)

ORIGINAL

If the exact behavior you described is what you are looking for, then override the following on your child view controller:

- (void)willMoveToParentViewController:(UIViewController *)parent; - (void)didMoveToParentViewController:(UIViewController *)parent; 

willMoveToParentViewController: will get called with parent != nil when entering, and parent == nil when leaving. didMoveToParentViewController: will always have parent != nil.

Sometimes, viewDidDisappear may make sense. However, if you're truly looking for push and pop from the parent container view controller, those methods above are what you want.

like image 34
greymouser Avatar answered Oct 14 '22 07:10

greymouser