3

I have a UIViewController called 'detailViewController'.

This view controller is accessed through multiple different segues using the push segue.

The problem I am facing is that the back button on the detailViewController takes the user back to the previous view controller (as it should), however I would like the back button to take the user to the masterViewController (the default UIViewController in the app).

How do I do this?

I have tried changing the segue types however that didn't really do anything at all.

Peter

Peter Stuart
  • 2,362
  • 7
  • 42
  • 73
  • If you don't want to go back to the root of your navigation controller please clarify your question. It's not clear what you're asking. For example, what is `masterViewController` in relation to your `detailViewController` ? – Aaron Feb 27 '14 at 17:43

5 Answers5

3

The method you're looking for is UINavigationController's popToRootViewControllerAnimated:

From the documentation: "Pops all the view controllers on the stack except the root view controller and updates the display."

You'll need to create a custom back button. You can't afaik override the back button's functionality.

So something like:

UIButton *myBackButton = [UIButton buttonWithType:UIButtonTypeCustom];
[myBackButton addTarget:self action:@selector(popToRoot:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *myCustomBackButtonItem = [[UIBarButtonItem alloc] initWithCustomView:myBackButton];
[self.navigationItem setLeftBarButtonItem:myCustomBackButtonItem];

and then the implementation of popToRoot: would look like:

- (void)popToRoot:(id)sender
{
    [self.navigationController popToRootViewControllerAnimated:YES];
}
geraldWilliam
  • 4,123
  • 1
  • 23
  • 35
0

Use the following code in order to go back to main view controller:

[self.navigationController popViewControllerAnimated:YES];

Edit: Based on the comments, I realize that my code takes you only one step back and may not answer what is asked in this question. Thanks.

Muhsin Zahid Ugur
  • 533
  • 1
  • 5
  • 14
  • 1
    actually this goes just one step back in your navigation stack... maybe try [self.navigationController popToRootViewControllerAnimated:NO]; – Yanchi Feb 27 '14 at 17:41
  • Let me know why you downvoted my answer. It works if you have a navigation controller. – Muhsin Zahid Ugur Feb 27 '14 at 17:42
  • Neither of them worked. The first suggestion just updated the navigation bar. You're suggestion updated it as the detailVC was loaded – Peter Stuart Feb 27 '14 at 17:42
  • @Mushin, what if the user has 4 view controllers pushed onto the navigation controller? This would only take them back once, not to the root. – Aaron Feb 27 '14 at 17:43
0

If the masterViewController you're talking about is the root you can call:

[self.navigationController popToRootViewControllerAnimated:YES];
Aaron
  • 7,055
  • 2
  • 38
  • 53
0

You can create the back button yourself and call [self.navigationController popToRootViewControllerAnimated:YES]. However, that does require you to create the back button yourself. An alternative option could be to take the current view controller, and remove all of them except the first and current ones:

NSMutableArray *viewControllers = [self.navigationController.viewControllers mutableCopy];
[viewControllers removeObjectsInRange:NSRangeMake(1, [viewControllers count] - 2)];
self.navigationController.viewControllers = viewControllers;
Scott Berrevoets
  • 16,921
  • 6
  • 59
  • 80
0

I came up with a workaround that looks up in a navigation controller's collection and find the offset between the existing and destination controller using name of destination controller and remove the in-between controller. Not sure if it is close to your need but give it a try:

- (NSArray *)navigateToViewController:(NSString *)destinationControllerName withControllers:(NSArray *)sourceControllers
{
    NSMutableArray *controllers = [[NSMutableArray alloc] initWithArray:sourceControllers];

    NSInteger sourceControllerIndex = [controllers count] - 1;  // Value should be index oriented instead of position oriented.
    NSInteger destControllerIndex = 0;

    // Find position of destination controller  (index oriented)
    for (UIViewController *controller in controllers)
    {
        NSString *controllerName = NSStringFromClass([controller class]);
        NSLog(@"class name: %@", controllerName);

        if([[controllerName lowercaseString] isEqualToString:[destinationControllerName lowercaseString]])
            break;

        destControllerIndex +=1;
    }

    // If desired controller does not exists in the stack, do not proceed.
    if (destControllerIndex == sourceControllerIndex)
    {
        return controllers;
    }
    // If destination is the same as source do not enter in this block
    // If destination and source controllers have zero or no controllers in between do not enter in this block
    // If destination and source controllers has few controllers (at least one) in between, go inside this block.
    // Here "destControllerIndex + 1" shows, there is at least one controller in between source and destination.
    else if(destControllerIndex + 1 < sourceControllerIndex)
    {
        NSLog(@"controllers in stack: %@", controllers);

        // Start from the controller following the source controller in stack and remove it
        // till the destination controller arrives
        for (NSInteger iterator = sourceControllerIndex - 1; iterator > destControllerIndex; iterator--)
        {
            UIViewController *cont = [controllers objectAtIndex:iterator];
            if(cont) {
            [cont release]; cont = nil; }
            [controllers removeObjectAtIndex:iterator];
            NSLog(@"controllers in stack: %@", controllers);
        }
    }

    return controllers;
}

and define it in some base controller:

-(void) popToViewController:(NSString *)controllerName withNavController:(UINavigationController *)navController
{
    // STStatistics refers a singleton class of common functions.
    NSArray *mArr = [STStatistics navigateToViewController:controllerName withControllers:navController.viewControllers];  

    navController.viewControllers = mArr;

    // There should be more than one controller in stack to pop.
    if([mArr count] > 1)
    {
        [navController popViewControllerAnimated:YES];
    }
}

and here is how called:

[self popToViewController:@"NameOfDestinationControllerInNavStack" withControllers:self.navigationController];
NeverHopeless
  • 11,077
  • 4
  • 35
  • 56
  • Your code has errors in it, and I am unsure where to place some of the code? – Peter Stuart Feb 27 '14 at 18:49
  • You might be getting non-arc error(s) if compiling on arc enabled. Remove all line(s) having `release` calls. Make a` BaseViewController :UIViewController` and inherit all UIViewControllers with this like : `detailViewController : BaseViewController` put first two snippet in base and write third one in `detailViewController`. – NeverHopeless Feb 27 '14 at 19:15