4

I'm switching views in the context of a navigation view heirarchy, and I want to be able to determine at switch time what the prior view was that is being pushed under the new view.

I'm trying this in a UINavigationControllerDelegate:

(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { NSLog( @"Switching from %@ to %@", NSStringFromClass( [[navigationController visibleViewController] class] ), NSStringFromClass( [viewController class] ) ); } 

I get this:

2009-08-05 20:05:21.274 App Name [85913:20b] Switching from ManagementScreen to ManagementScreen

unfortunately it appears that before "will" is called, it is already swapped out in the state of the UINavigationController such that viewController passed in is always the same as the visibleViewController on the UINavigationController (and also the topViewController property, not demonstrated here but I tried it with the same code).

I would like to avoid extending the navigation view controller, and honestly while I can easily put a property on the delegate - however I'm wondering if this behavior is possible within the existing framework (seems will should be called before it happens where as did happens after, but it seems the state of the navigation controller is modified before either).

Thanks!

1
  • FYI, it's simpler to use NSStringFromClass(); Commented Aug 6, 2009 at 0:33

2 Answers 2

5

I don't think the answers that use the UINavigationControllerDelegate work because, as the question points out, by the time the delegate is called the view controller that will be displayed is already the value for navigationController.topViewController and navigationController.visibleViewController.

Instead, use observers.

Step 1. Set up an observer to watch for the UINavigationControllerWillShowViewController notification:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewControllerChange:) name:@"UINavigationControllerWillShowViewControllerNotification" object:self.navigationController]; 

Step 2. Create the notification callback (in this example called viewControllerChange) and use keys in the notifications userInfo dictionary to see the last and next view controllers:

(void)viewControllerChange:(NSNotification *)notification { NSDictionary *userInfo = [notification userInfo]; NSLog(@"Switching from %@ to %@", [[userInfo objectForKey:@"UINavigationControllerLastVisibleViewController"] class], [[userInfo objectForKey:@"UINavigationControllerNextVisibleViewController"] class]); } 
Sign up to request clarification or add additional context in comments.

3 Comments

This really works. But I can't find any documentation on that notification, is it private? Will I get in trouble if I submit an app. using it?
Nope. Won't get in trouble. Notifications are a core part of the API. Apple documents this in the "Cocoa Fundamentals Guide" in the section titled "Communicating with objects"
Thanks for the answer Dan. It's so bad that the delegate calls when the UIViewController is not in the stack anymore.
2
- (void)navigationController:(UINavigationController*)nc didShowViewController:(UIViewController*)vc animated:(BOOL)animated { NSLog(@"Switching from %@ to %@", NSStringFromClass([vc class]), NSStringFromClass([[nc.viewControllers objectAtIndex:[nc.viewControllers count]-1] class])); } 

2 Comments

Good, except it doesn't always work: setViewControllers:: will overwrite viewControllers property and if you're popping to the root you're going to understep the array boundary (which is of course easy to avoid, but the overwriting of the controller stack dunno!)
Of course you should add guards for that, and you're not supposed to pop the root anyway. As for setViewControllers -- he specifically said that he was pushing in his case.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.