Alexi Groove
Alexi Groove

Reputation: 6686

How to trap the back button event

I have a UITableViewController that launches a UIViewController and I would like to trap whenever the back button is pressed in the child controller, which is the class that derives from 'UIViewController'. I can change the Back Button title but setting the target & action values when setting the backBarButtonItem seems to get ignored. What's a way to receiving some kind of notification that the Back button was tapped?

- (void)showDetailView 
{
    // How I'm creating & showing the detail controller
    MyViewController *controller = [[MyViewController alloc] initWithNibName:@"MyDetailView" bundle:nil];   

    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Pages"
                            style:UIBarButtonItemStyleBordered 
                            target:self                                     
                            action:@selector(handleBack:)];

    self.navigationItem.backBarButtonItem = backButton;
    [backButton release];

    [self.navigationController pushViewController:controller animated:animated];
    [controller release];

}   

- (void)handleBack:(id)sender
{
    // not reaching here
    NSLog(@"handleBack event reached");
}

Upvotes: 18

Views: 28651

Answers (8)

Shawn Frank
Shawn Frank

Reputation: 5143

This seems possible now as of iOS16+ with the help of backAction

Here is what the documentation says:

If a back button already appears in the navigation bar, setting this property replaces its action without modifying its appearance.

So in your viewDidLoad or somewhere appropriate, you can add this code:

navigationItem.backAction = UIAction { [weak self] _ in
    // Handle your other logic here for back button tap
    self?.navigationController?.popViewController(animated: true)
    
}

Upvotes: 0

Udo Günther
Udo Günther

Reputation: 1

Simply use viewDidDisappear instead. It will be perfectly called in any scenario.

We are basing your lifecycle management on viewDidAppear and viewDidDisappear. If you know Android: the both are comparable to onResume and onPause methods. But there is a difference when it comes to locking the screen or pressing the homebutton on iOS.

Upvotes: -2

Blank
Blank

Reputation: 4892

In my opinion the best solution.

- (void)didMoveToParentViewController:(UIViewController *)parent
{
    if (![parent isEqual:self.parentViewController]) {
         NSLog(@"Back pressed");
    }
}

But it only works with iOS5+

Upvotes: 14

PRASANTH P.C
PRASANTH P.C

Reputation: 11

{
    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"back"
                                                                   style:UIBarButtonItemStyleBordered 
                                                                  target:self                                                                             
                                                                  action:@selector(handleBack:)];
    self.navigationItem.leftBarButtonItem = backButton;
    [backButton release];
    [self filldata];
    [super viewDidLoad];
}

just replace backBarButtonItem with leftBarButtonItem

Upvotes: 1

m8labs
m8labs

Reputation: 3721

I use this code:

- (void) viewWillDisappear:(BOOL)animated {

   if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound)
   {
      // your view controller already out of the stack, it meens user pressed Back button
   }
}

But this is not actual when user presses tab bar button and pops to root view controller at one step. For this situation use this:

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


- (void) viewControllerChange:(NSNotification*)notification {

   NSDictionary* userInfo = [notification userInfo];

   if ([[userInfo objectForKey:@"UINavigationControllerNextVisibleViewController"] isKindOfClass:[<YourRootControllerClass> class]])
   { 
      // do your staff here
   }
}

Don't forget then:

   [[NSNotificationCenter defaultCenter] removeObserver:self
                                                   name:@"UINavigationControllerWillShowViewControllerNotification"
                                                 object:self.navigationController];

Upvotes: 9

Andrew
Andrew

Reputation: 395

It has been a while since this was asked, but I just tried to do this myself. I used a solution similar to Zoran's, however instead of using a flag I did this:

- (void)viewWillDisappear: (BOOL)animated
{
    [super viewWillDisappear: animated];
    if (![[self.navigationController viewControllers] containsObject: self])
    {
        // the view has been removed from the navigation stack, back is probably the cause
        // this will be slow with a large stack however.
    }
}

I think it bypasses the issues with flags and IMO is cleaner, however not as efficient (if there are lots of items on the navigation controller).

Upvotes: 17

Zoran Simic
Zoran Simic

Reputation: 10333

You can implement the viewWillDisappear method of UIViewController. This gets called when your controller is about to go away (either because another one was pushed onto the navigation controller stack, or because the 'back' button was pressed).

To determine whether the view is disappearing because of the back button being pressed, you can use a custom flag that you set wherever you push a new controller onto the navigation controller, like shown below

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    if (viewPushed) {
        viewPushed = NO;   // Flag indicates that view disappeared because we pushed another controller onto the navigation controller, we acknowledge it here
    } else {
        // Here, you know that back button was pressed
    }   
}

And wherever you push a new view controller, you would have to remember to also set that flag...

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ...
    viewPushed = YES;
    [self.navigationController pushViewController:myNewController animated:YES];
    ...
}

Upvotes: 19

coneybeare
coneybeare

Reputation: 33101

You can make your own button and place it as the leftBarButtonItem. Then have it call your method where you can do whatever, and call [self.navigationController popViewController... yourself

Upvotes: 1

Related Questions