14

I'm working on an iOS5 app using storyboard, and I have a method in a view controller class that i'd like to access from the App Delegate. The trouble is, this view controller gets instantiated via a tab bar controller in storyboard, so the App Delegate has no direct way of calling the method I want...

For a view controller to get in touch with the App Delegate, all one has to do is use:

MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];

Is there a similarly easy way of pointing to an already-instantiated view controller or class?

Amos
  • 868
  • 1
  • 10
  • 22

7 Answers7

15

Thanks to Jerry (above), here's the code that got me what I wanted:

    UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
MasterViewController *result;

//check to see if navbar "get" worked
if (navigationController.viewControllers) 

    //look for the nav controller in tab bar views 
    for (UINavigationController *view in navigationController.viewControllers) {

        //when found, do the same thing to find the MasterViewController under the nav controller
        if ([view isKindOfClass:[UINavigationController class]])
            for (UIViewController *view2 in view.viewControllers) 
                if ([view2 isKindOfClass:[MasterViewController class]])                    
                    result = (MasterViewController *) view2;
}
Amos
  • 868
  • 1
  • 10
  • 22
10

I probably would do it in reverse. Create a method in AppDelegate call registerViewController or something. In every ViewController, call the method with itself with a name. Then in AppDelegate, you can do whatever you want afterward. It is messy to do all sort of drill

In AppDelegate

- (void)registerViewController:(NSString *)name controller:(UIViewController *)controller
{
    if(_viewControllers == nil)
    {
        _viewControllers = [[NSMutableDictionary alloc] init];

    }

    [_viewControllers setObject:controller forKey:name];
}

In any ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    [appDelegate registerViewController:@"feelings" controller:self];
}

In AppDelegate

XViewController *vc = (XViewController *)[_viewControllers objectForKey:@"X"];
[X startSpinner];

Hope this help

BS

Billy Sun
  • 121
  • 1
  • 4
  • great idea,but XViewController should be remove from _viewControllers when dealloc and I must remember many keys if there are many view controllers I need to access in app delegate. – Nick Nov 05 '13 at 08:18
10

You'll have to traverse the view hierarchy from the app delegate. Assuming the AppDelegate holds a reference to the UITabBarController, you could use the viewControllers property or selectedViewController property to get to your view controller.

Rinju Jain
  • 1,694
  • 1
  • 14
  • 23
Jerry
  • 4,382
  • 2
  • 35
  • 29
  • So...an outlet from the tab bar in storyboard to the app delegate, and then figure out the tab bar's properties to find the view controller I need? Any reason not to just create a direct outlet from the view controller itself, since that's in storyboard too? – Amos Jan 09 '12 at 05:35
  • 6
    Ok, there is no way to create an outlet to the app delegate from the storyboard, so my statement was a little incorrect. There is a window property on the app delegate that is set automatically by the storyboard and it has a rootViewController property. That will be the first view controller in the storyboard. From there you should be able to get to the view you need. – Jerry Jan 09 '12 at 13:45
  • Bam! That did it...though it is a bit of a pain traversing all the views. Thanks, Jerry! – Amos Jan 09 '12 at 16:44
  • @jerry can u suggest some solution for a similar issue of mine. http://stackoverflow.com/questions/21373470/access-a-view-controller-from-appdelgate-using-storyboard – Suraj K Thomas Jan 31 '14 at 10:18
7

If you are using a storyboard, and you want instance of a viewController in storyboard you can use the following

UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
id viewcontroller = [mystoryboard instantiateViewControllerWithIdentifier:@"identifier"];

Here the 'identifier' is the name provided in the particular viewController's 'storyBoard ID' in 'Identity' section in 'Identity Inspector'.

Dilip Manek
  • 9,095
  • 5
  • 44
  • 56
infiniteLoop
  • 2,135
  • 1
  • 25
  • 29
  • This worked great. Would you have any guidance on how to also load my tab bar and navigation controllers? – mreynol Dec 11 '14 at 23:51
6

I have a better solution. You can use window.rootViewController.storyboard to get a reference to the storyboard of that view.

Stéphane Bruckert
  • 21,706
  • 14
  • 92
  • 130
Steffen Brem
  • 1,738
  • 18
  • 29
2

In the AppDelegate, you could simply use indexes to access the controllers via UITabBarController:

UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
firstViewController = [[tabBarController viewControllers] objectAtIndex:0];
secondViewController = [[tabBarController viewControllers] objectAtIndex:1];
thirdViewController = [[tabBarController viewControllers] objectAtIndex:2];

Naturally, this will get messed up if you change the ordering of the tab bar. Also, if you're looking for a controller deeper in the hierarchy, you need to do a bit more legwork.

Pirkka Esko
  • 718
  • 9
  • 13
1

Swift

This is the Swift version of @infiniteLoop's answer.

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myViewController = storyboard.instantiateViewControllerWithIdentifier("identifier") as! MyViewController

You need to replace the storyboard name, view controller name, and view controller identifier with whatever you used in your project.

Related tasks

Community
  • 1
  • 1
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393