29
votes

I'm presenting a ViewController modally. How can I access the parent view controller ?

My architecture is TabBarController=>VC1=>VC2=>VC3=>MVC1, and I want to reach VC3 from MVC1.

In VC3, I have this code :

- (void) editAd{
    AskPasswordViewController *modalViewController = [[AskPasswordViewController alloc] initWithNibName:@"AskPasswordView" bundle:nil];

    NSLog(@"modalparent class=%@", [[modalViewController parentViewController] class]);

    [self presentModalViewController:modalViewController animated:YES];
    [modalViewController release];
}

I tried this in MVC1:

- (void) sendRequest {
    NSLog(@"classe : %@",[[self parentViewController] class] );
}

but it returns my TabBarViewController...

7

7 Answers

94
votes

You can access parent by calling:

self.presentingViewController

As per apple documentation:

The view controller that presented this view controller (or its farthest ancestor.)

25
votes

The way I'd go about something like this is to simply create a delegate. In AskPasswordViewController's header, put

id delegate;

and

@property (nonatomic, assign) id delegate;

Synthesize it in the implementation file. Then after you alloc/init the modal controller, and before you present it, set modalViewController.delegate = self;. Then within the modal controller, you can call self.delegate to get information from the view controller that presented it. I hope this helps

7
votes

You can always go further back just by calling parentViewController like so:

self.parentViewController.parentViewController .... and so on until you reach the right one.

5
votes

Addition to Vibhor Goyal - Sometimes, self.presentingViewController registers as NavigationController. Therefore try:

if let vc = self.presentingViewController.childViewControllers.last as? YourViewController {
// do stuff here
}
1
votes

Here I came up with universal method to navigate from any place to root.

  1. You create a new Class file with this class, so that it's accessible from anywhere in your project:

    import UIKit
    
    class SharedControllers
    {
        static func navigateToRoot(viewController: UIViewController)
        {
            var nc = viewController.navigationController
    
            // If this is a normal view with NavigationController, then we just pop to root.
            if nc != nil
            {
                nc?.popToRootViewControllerAnimated(true)
                return
            }
    
            // Most likely we are in Modal view, so we will need to search for a view with NavigationController.
            let vc = viewController.presentingViewController
    
            if nc == nil
            {
                nc = viewController.presentingViewController?.navigationController
            }
    
            if nc == nil
            {
                nc = viewController.parentViewController?.navigationController
            }
    
            if vc is UINavigationController && nc == nil
            {
                nc = vc as? UINavigationController
            }
    
            if nc != nil
            {
                viewController.dismissViewControllerAnimated(false, completion:
                    {
                        nc?.popToRootViewControllerAnimated(true)
                })
            }
        }
    }
    
  2. Usage from anywhere in your project:

    {
        ...
        SharedControllers.navigateToRoot(self)
        ...
    }
    
0
votes
//You have to get the root, iterate through the root's ViewControllers and then ask for the ParentViewController.
    UINavigationController ​*root = (UINavigationController*​)[[(AppDelegate*) [[UIApplication sharedApplication]delegate] window] rootViewController];
           for (UIViewController *VC in root.viewControllers) {
               if([VC isKindOfClass:[YourParentViewController class]]){
                   YourParentViewController*  parent = (YourParentViewController*)VC;
                   [parent callMethod]; // your code here
                   [self dismissViewControllerAnimated:YES completion:nil];
               }
           }
0
votes

If presentingViewController gives you unexpected results and you don't want to fiddle with it, just do:

class MyViewController: UIViewController {

    private weak var presenter: UIViewController?

    init(presenter: UIViewController) {
        self.presenter = presenter
        super.init(nibName: nil, bundle: nil)
        ...
    }
    
    ...
}