Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass value between NavigationController and ViewController with StoryBoard?

I have a problem,
The following is my StoryBoard,
the first Controller is a TabBarController,
and it relation with A (ViewController).

How can I pass value between NavigationController and ViewController with StoryBoard?
A is a ViewController,
B is a NavigationController, A change page to B by modal segue
C is a ViewController, C will change to another page by push so I need a NavigationController

OK, I want to pass value from A to C,
now I can pass value from A to B by prepareForSegue,
However, because B and C have relationship but not segue,
So I can't pass value from B to C by prepareForSegue!!!

How can I pass value between NavigationController and ViewController with StoryBoard?

like image 276
Azure Chen Avatar asked Jan 13 '13 19:01

Azure Chen


1 Answers

The Storyboard image is a little misleading here.

When you segue to B, actually you are segueing to the B/C combo as NavControllers always have at least one viewController in their stack (which is their topViewController and their [viewControllers objectAtIndex:0]).

So you do have a relationship directly from A to C.

How you access that controller depends on whether your segue is modal or push. In your case it is modal, but I will describe both so you can see the difference.

In either case, to pass data to C, you need to declare a property in it's header file

    @interface CviewController: UIViewContrller
    @property (assign) int dataFromA;
    @end

push segue

In a push segue, it is actually C that is the destinationViewController, not B. In fact the push segue is governed by B, which is the UINavigationController for both A and C. The code behind the push segue is of the form
[self.navigationController pushViewController:otherViewController];

In AviewController's prepareForSegue:

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
        {
         CviewController* controller = segue.destinationViewController;
        [controller setDataFromA:self.data];
    }

It is possible in the storyboard to make a push segue line between two viewControllers that do not share a common UINavigationController. However when you run this you will get a crash error:

'Could not find a navigation controller for segue 'pushC'. Push segues can only be used when the source controller is managed by an instance of UINavigationController.'

Behind every good push segue lies a Navigation Controller.

modal segue

The code hiding behind a modal Segue is the UIViewController method
- (void)presentViewController:(UIViewController *)viewControllerToPresent

In a modal segue to a NavController/ViewController combo, the destination viewController is whatever the segue line points to. If it points to a viewController, that is the segue.destinationController (and the UINavigationController will be ignored, which is not what you want here); if it points to a UINavigationController, as in this case, that will be it's destinationController. But it is still straightforward to access the viewController, as it will be the navigation Controller's topViewController.

In AviewController's prepareForSegue:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
     CviewController* controller = 
        (CviewController*)[[segue destinationViewController] topViewController];
    [controller setDataFromA:self.data];
}

Note that in this case we have to use old-style [[message passing] syntax]. If we use modern.property.syntax we get a compile error. That's because the program does not know the type of desinationViewController, and refuses to accept topViewController as a property of an unknown type. But it is happy to [send [real messages]] to an unknown type. We also have to (typecast*) to avoid compiler warnings.

like image 174
foundry Avatar answered Oct 21 '22 07:10

foundry