Question

I have a UINavigationController ans a chain of 3 simple controllers. Each one has a button. When press a button a next controller is Pushed. ViewController1 -> ViewController2 -> ViewController3. When I push a back button on the 3rd view i want to move to the first view. Using of backBarButtonItem is obligatory. Here is the code for second controller:

#import "ViewController2.h"

static BOOL isBackButtonPressed;

@implementation ViewController2

- (void)viewDidLoad {
    self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"back from 3" style:UIBarButtonItemStyleBordered target:nil action:nil];
    [super viewDidLoad];
}

- (void)viewWillAppear:(BOOL)animated {
    if (isBackButtonPressed) {
        [self.navigationController popViewControllerAnimated:YES];
    } else {
        isBackButtonPressed = YES;
    }
    [super viewWillAppear:animated];
}

@end

But when I press back button on the third view I return to the second view instead of the first view. Could you help me to return to the first view pressing back button on the third view. I tried suggestions from answers but they don't help.

  1. Adding a selector to backBarButtonItem doesn't help because it is never called.
  2. Adding a [self.navigationController popToRootViewControllerAnimated:YES] in viewWillDisappear methos also doesn't work. I don't know why. I think that the actual problem is how backBarButtonItem works. Any other suggestions?

The behaviour I try to achieve exists in the calendar on iPhone. When you rotate iPhone to landscape you get to the weeek view. Then go to the event details, and rotate to the portrait. When you press back button you will get to a day view not to a week view, so a controller with weekview is skipped.

Was it helpful?

Solution

After countless number of tries my solution was simply not use backBarButtonItem! As whatever i do it always goes to previous viewController instead of calling its selector

Instead I use only leftBarButtonItem for navigation, as it guarantees calling my action.

Here an example

UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 27, 22)];
[backButton setImage:[UIImage imageNamed:@"backbutton"] forState:UIControlStateNormal];
    [backButton addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];

  self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];

This certainly calls backButtonPressed action.. This works both for IOS 6 and 7

OTHER TIPS

No need to register a new selector for the back button, just do:

-(void)viewWillDisappear{
    if ( [self.navigationController.viewControllers containsObject:self] )
         //It means that the view controller was popped (back button pressed or whatever)
         //so we'll just pop one more view controller
         [self.navigationController popViewControllerAnimated:NO];
}

in your ViewController3 viewWillDisappear method

Try using this in your third view controller, this way you check if you have pressed the back button and directly pop to the root view controller which as you stated is your first view controller.

-(void) viewWillDisappear:(BOOL)animated {
    if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    [super viewWillDisappear:animated];
}

I had the same problem as you beofre and fixed it like this:

You can capture the back button on the ViewController3 and before poping the view, remove ViewController2 from the navigation stack like this:

- (void)viewDidLoad {
   [super viewDidLoad];
   self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"back from 3" style:UIBarButtonItemStyleBordered target:self action:@selector(customBackPressed:)];
}

-(void)customBackPressed:(id)sender {
        NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray: navigationController.viewControllers];
        for (UIViewController *vc in viewControllers)
        {
        // If vc is ViewController2 type, remove it
        }

        navigationController.viewControllers = allViewControllers;

       [self.navigationController popViewControllerAnimated:YES];
 }

Because ViewController2 is not in the stack anymore, it will jump to ViewController1.

Also, if ViewController1 is the root view controller, you can just do:

[self.navigationController popToRootViewControllerAnimated:YES]; 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top