I have a problem,
The following is my StoryBoard,
the first Controller is a TabBarController,
and it relation with A (ViewController).
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?
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.
Related
I have 3 viewControllers. viewController1 is linked to viewController2 (via segue id "first"), and viewController2 is linked to viewController3 (via segue id "destinationController"). I'm trying to segue from viewController1 to viewController3. Here is my code:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"DestinationController"];
[self.navigationController pushViewController:controller animated:YES];
It crashed with the following error:
'Storyboard (<UIStoryboard: 0x7fb1a944be00>) doesn't contain a view controller with identifier 'DestinationController''
How can I segue 2 viewControllers without connecting the first to the last? (I prefer not adding a segue from the storyboard because it will get very messy.)
The error is telling you that you don't have a controller with the identifier, "DestinationController". From the text in your question, it seems that you have a segue identifier called "DestinationController", but that's a different thing from an identifier on the controller, which you set in the Identity Inspector with the "Storyboard ID" field.
I think it would be more consistent though, to make a segue from the first to the third view controller. It also makes the navigation among your controllers clearer in the storyboard.
Please check "DestinationController" segue is bind with you current ViewController in which you write this code.
If you perform segue from VC1 to VC3 there is only one way in your case you have to go through VC2 (You can place conditions on viewDidLoad method of VC2 to perform segue with VC3).
Please bind "DestinationController" to your current controller and your error will gone.
This may help you :)
UIViewController3 *controller3 = [self.storyboard instantiateViewControllerWithIdentifier:#"DestinationController"];
[self.navigationController pushViewController: controller3 animated:YES];
Don't forget the set the storyboardId "DestinationController" not the segue name, Check the below Link,
Check the answer
I have added a segue between two view controllers using XCode 6 interface builder. However it calls the default constructor. How can I get it to call a specific constructor for the second view?
view 1 -> click button -> activates segue -> calls constructor of view 2 -> displays view 2
Using a segue this is unfortunately not possible, you can't further specify how the destinationViewController should be instantiated.
However, instead of using the Storyboard segue, you can instantiate the UIViewController yourself and just push it manually onto the navigation stack.
- (IBAction)buttonTap
{
ViewController2 *vc2 = <your custom constructor>;
[self.navigationController pushViewController:vc2 animated:YES];
}
(note that this mimics the exact same behaviour that the push segue gives you)
Otherwise, if you want to keep on using the Storyboard segue and your actual goal is to initialize certain properties of ViewController2, you can implemented prepareForSegue: and set the properties there.
- (void)prepareForSegue:(UIStoryboardSegue *)segue
{
ViewController2 *vc2 = segue.destinationViewController;
// set properties here
vc2.prop = xyz;
}
(note the code is not tested but it should convey the main ideas, let me know if you need further explanation)
My hierarchy
UINavigationController -> UIViewController
-> UITabViewController
-> ViewController1
-> ViewController2
-> ViewController3
I want to navigate back from
ViewController1 -> UIViewController.
Anyone know please solve this issues.
"Unwind" is your answer.
Create an IBAction method to unwind segue. Define this method in a controller in which you want to unwind (Controller from you want to jump back to main controller).
- (IBAction) prepareForUnwind:(UIStoryboardSegue *)segue {
}
Now connect back button (in this case "Home" button) with this method in Storyboard. To connect unwind action -> Ctrl-drag to "Exit" outlet button of your controller.
Note: If you are using Xcode version less than 6.0 than "Exit" outlet is located at bottom of your view controller.
This will navigate back to your root navigation controller. That is UIViewController.
For further separation you can give an identifier to unwind segue and make different actions for exit to last controller.
Select identifier from left list and give an identifier in Attributes inspector.
Key points:
Write unwind method in a controller which will be exited.
Connection to "Exit" delegate will only works after you define unwind method.
Ctrl+Drag from a control to the Exit symbol to select the unwind segue you want this control to perform
Unwind segues appear below the Exit symbol for each connection made
You can give those unwind segues an identifier to have different activities performed.
You can use
[navigationController popToViewController:<#(UIViewController *)#> animated:<#(BOOL)#>];
just provide the instance of the viewController you want to pop to and set animated property to YES if u want pop with animation and NO if not.
Here the controller UIViewController is the rootViewController of UINavigationController. So you just need to pop to the rootViewController from the ViewController1
[self.navigationController popToRootViewControllerAnimated:YES];
You can done by this:
ViewController *loginVC = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController popToViewController: loginVC animated:YES]
Here's a quick and dirty question:
I have a "main" view controller (VC) which is opened up from a parent VC, that uses a navigation controller. Then I have a "sub" VC that is opened (modal segue) from the "main" VC.
I have set a property in the main VC's interface:
#property (nonatomic) int myVar;
Then set it from the button's action that is touched to display the "sub"VC from the "main"VC's interface:
self.myVar=1;
I imported the mainVC.h in the subVC.h
Then at the viewDidLoad method of the subVC, I'm trying to access myVar's value, but can't do that with:
NSLog(#"Myvar is %i", ((mainVC*)self.parentViewController).myVar);
Which returns the value as 0.
And when I try presentingViewController method instead, I get an error (which did not cause the error when I pushed the segue instead of making it a modal:
[MainVC myVar]: unrecognized selector sent to instance
I'm trying to code for iOS 5, and needless to say that I'm still a noob.
What am I missing?
Thanks!
The parentViewController of the "sub" view controller is not the mainVC, it's the navigation controller. The mainVC is not accessible - for all you know, it may be deallocated to save memory.
If you need to pass data from the main controller to the sub controller on the segue, add an instance variable to the "sub" view controller, and set it in the prepareForSegue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"open_sub"]) {
subVC *sub = segue.destinationViewController;
sub.myVar = 1;
}
}
I still haven't grasped this transfer with the structure below. I have read many posts, and have seen the same unanswered post by others, but no resolution.
I will try to simplify the question to make it easier for all.
The structure of the project is:
UITabbar with tab1 and tab2
Tab1 has a Nav controller-->ViewController1
Tab2 has a Nav controller -->ViewController2
In viewcontroller1 (tab1) I have object X.
In ViewCOntroller2 (tab2) I want to display object X.
Don't worry about displaying, that's the easy part.
Question: How do you pass object X from tab1 to tab2. (what is the general pattern).
If you want to do it using prepareForSegue, is this ok, or is there a better way.
If using prepareForSegue, where do you drag the segue to?
The tabbarcontroller
OR*****
2. to the second VC
Hopefully this is clear enough. With this in mind how would you perform the transfer?
Using the segue 1:
I tried doing this:
//(From View controller 1)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"CreateObjectXToDisplayObjectX"])
ViewController2* vc2 = [[ViewController2 alloc] init];
UITabBarController* tbc = [segue destinationViewController];
vc2 = (ViewController2 *)[[tbc customizableViewControllers] objectAtIndex:1];
//Crash here with with [MainNavigationControllerDesign setViewController1Delegate:]: unrecognized selector sent to instance 0x1064ef70'
vc2.viewController1Delegate=self;
vc2.objectXAtViewController2 = _objectXFromViewController1;
}
}
So, how is this Object X transfer accomplished?
Thank you in advance
You don't want to use segues in this way. Segues always instantiate new controllers when you go to them, but you already have these controllers embedded in the tab bar controller. If you were setting this up in code, I would say use a delegate, but if you set this up in IB, it's hard to do that. From VC2, you can get a reference to VC1's navigation controller with self.tabBarController.viewControllers[0]. VC1 will be that navigation controller's topViewController, so, putting that together, and adding a cast, you can access VC1 like this:
ViewController1 *vc1 = (ViewController1 *)[self.tabBarController.viewControllers[0] topViewController];
Once you have that reference, you can access any of vc1's properties. Don't forget to import ViewController1.h into ViewController2's .m file.