user1046037
user1046037

Reputation: 17695

Pass data across child navigation controllers

Overview

I have an iOS project which contains 2 navigation controllers as shown in the pic attached below.

I would like to pass some data when it segues from AAA to CCC but there is a navigation controller between AAA and CCC.

enter image description here

According to Apple's documentation, UINavigationController shouldn't be subclassed, so I can't create a delegate and pass data.

Question:

Upvotes: 7

Views: 3754

Answers (3)

JWK
JWK

Reputation: 3780

For anyone who is unclear on how to implement the accepted answer, here is a code example to more clearly explain how to "have a pointer to the navigation controller." The following code passes an NSString from AAA (AAAViewController) to CCC (CCCViewController) with an identifier named "ToCCC" for the segue.

1) Create a pointer to foo in CCCViewController.h.

//  CCCViewController.h

#import <UIKit/UIKit.h>

@interface CCCViewController : UITableViewController

@property (strong, nonatomic) NSString *foo;

@end

2) In AAAViewController.m, create a pointer to CCCViewController (via the navigation controller) and then set foo.

//  AAAViewController.m

#import "AAAViewController.h"
#import "CCCViewController.h" // Note the import statement for CCC.

@implementation AAAViewController

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString: @"ToCCC"])
    {
        CCCViewController *ccc = [[segue.destinationViewController viewControllers] objectAtIndex: 0];
        ccc.foo = @"A string passed from AAA";
    }
}

@end

3) Do something with foo in CCCViewController.m (e.g. log it to the console).

//  CCCViewController.m

#import "CCCViewController.h"

@implementation CCCViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Log foo to the console.
    NSLog(@"%@", _foo);
}

@end

Upvotes: 4

Chad Edrupt
Chad Edrupt

Reputation: 1584

A nice solution is to create a category on UIStoryboardSeque

UIStoryboardSegue+TopLevel.h

@interface UIStoryboardSegue (TopLevel)

@property (readonly) id topLevelDestinationViewController;

@end

UIStoryboardSegue+TopLevel.m

@implementation UIStoryboardSegue (TopLevel)

- (id)topLevelDestinationViewController
{
    id dest = self.destinationViewController;
    if ([dest isKindOfClass:[UINavigationController class]]) {
        UINavigationController* nav = dest;
        dest = nav.topViewController;
    }
    return dest;
}

@end

Then to use the category

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [super prepareForSegue:segue sender:sender];

     if ([[segue topLevelDestinationViewController] respondsToSelector:@selector(setSomeProperty:)]) 
     {
        [[segue topLevelDestinationViewController] performSelector:@selector(setSomeProperty:) withObject:self.someProperty];
     }
}

That way your code can become very generic, and it doesn't matter if the destination view controller for the segue is a navigation controller or not

Upvotes: 0

jsd
jsd

Reputation: 7703

If you have a pointer to the navigation controller, you can get its viewControllers array. In that array, objectAtIndex:0 will be CCC.

Upvotes: 9

Related Questions