I have 3 MVCs and name them A, B, C here.
A is the main MVC with a button "Menu" connected to B with popover segue.
A also connected to C with a manual show segue.
B is a popover MVC with a button "Detail" connected to A with unwind segue.
C is the detail MVC with detail info.
Inside the unwind function of A. I call performSegueWithIdentifier to show C.
Expected behavior is
Click "Detail" button in B
B disappear and A show up
C show up
But running the app I got.
Click "Detail" button in B
B disappear and A show up
C show up
C disappear and A show up
C show up and disappear suddenly which is not what I want.
Some additional info
Popover B is needed for more buttons.
A is embeded in a UINavigationController. Connecting A -> C rather than B -> C, for a Back button on top of C.
Seems unwind function is not the correct place to call performSegueWithIdentifier.
UIKit will pop view controller after calling the unwind function.
Thus push new view controller inside unwind function will pop quickly.
The solution is to delay performSegueWithIdentifier.
Solution 1: NOT WORKING FINE
Adding an bool instance and inside viewDidAppear use this instance to determine if we perform segue.
Won't work if B controller is a popover. After B popover disappear, viewDidAppear is not called for A controller.
Solution 2: WORKING
Push performSegueWithIdentifier into main queue.
#IBAction func unwind(segue : UIStoryboardSegue) {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("SomeSegue", sender: self)
}
}
you can easily switch between the viewControllers by assigning storyboard id to them using below code ..
// you need to create UIStoryboard object by giving name of your storyboard
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
// here you need to create storyboard ID of perticular view where you need to navigate your app
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"viewContIdentifire"];
// if use presentViewController this will not enables you to go back to previous view
[self presentViewController:vc animated:NO completion:nil];
**// OR**
// using pushViewController lets you to go back to the previous view
[self.navigationController pushViewController:vc animated:YES];
Or still you want to work with segue so must gain control over them by implementing its delegate method below so they perform accordingly.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segueName"]) {
// perform segue
[self performSegueWithIdentifier:#"SegueIdentifier" sender:self];
}
}
happy coding .. :)
Related
I have a 3 viewcontroller navigation where A presents modal controller B, which presents modal controller C all via segues. C has an unwind segue back to B. It also has an unwind back to A. When I perform action for C to unwind to B, it unwinds but then pops B and goes back to A. This is not what I want, I want it in this case to stay on B. Below are the segues VC C uses.
unwindCancel is for when user clicks on a collectionViewCell and goes back to VC B.
prepareForUnwind is just a standard "cancel" button to VC A.
Below is code for didSelectItem to call the unwind in VC C. Below that is prepareForSegue in VC C.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:#"unwindCancel" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"unwindCancel"]) {
GalleryDetailViewController *detailVC = segue.destinationViewController;
detailVC.colletionCount = self.indexPathToPass;
}
}
VC B unwind in .m file
-(IBAction)unwindCancel:(UIStoryboardSegue *)segue{
[self.collectionView scrollToItemAtIndexPath:self.colletionCount atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
}
VC A unwind in .m file
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
}
When going from C to B, don't use an unwind segue just have C call dismissViewController. If you're committed to using unwind segues, look here specifically section entitle How an Unwind Segue Determines its Destination View Controller
I guess you confused an unwind-segue's identifier with unwind-segue's Action method.
If you build an unwind-segue with "prepareForUnwind" action, and then you change this unwind-segue's identifier to "unwindCancel".The problem would appear.
Just make sure the unwind-segue's identifier matches it's action method.
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]
I have 3 view controllers: A, B and C. A is initial and it has 2 buttons: one is redirecting to B, and second one to C. When B is pushed, and button within B pressed user is redirected to C. Now on navigation bar within C, when I press back button I want to be redirected to A always, and never to B. Is that possible?
This is base functionality I want to achieve:
a)
A->B->C C back to A
b)
A->C C back to A
for (UIViewController *controller in self.navigationController.viewControllers)
{
if ([controller isKindOfClass:[A class]])
{
[self.navigationController popToViewController:controller
animated:YES];
break;
}
}
you can achieve this with presentview controller as modal view.first from a if first button is pressed present b view.if secnd button is pressed present c view and in c view controller put back button and add delegates and implement the delegate in a view controller.and you will have to dismiss one view after the other in a view controller.
The only way is replacing the back button by a custom button.
After reading what you said I think you meant implementing custom actions for each button.The way I would do it(In Swift) is this:
#IBAction func pressButton(sender : UIButton){
var SecondView :ViewController2
SecondView = self.storyboard?.instantiateViewControllerWithIdentifier("SecondView") as ViewController2
self.presentViewController(SecondView, animated: true, completion:nil)
self.viewWillDisappear(true)
}
This method I have used a lot and I know there is another way using segues but you still use #IBActions.You just create a new segue(identifier) and in the prepareforSegue method you say what happens when that segue is triggered
I have used a storyboard and dragged the navigations between controllers . E.g From UIViewController A to UIViewController B to UIViewController C.
I have a button on UIViewController A. I am using that button and linking an action dragging to UIViewController B and setting the segue to push type.
Then on the button Click,I am checking some condition like this :
if( go == YES )
{
// navigate to B
}
else
{
// don't navigate to B
}
How can I write the code to properly navigate to B or stop navigating to B?
Do I have to use prepareForSegue?
Till here, you have done it correctly. Now try these steps :
The segue that you have connected by dragging from A to B, set the segueIdentifier for it in the Interface Builder.
In your button click method, use this statement when you want to navigate from A to B.
[self performSegueWithIdentifier:#"yourSegueIdentifier" sender:nil];
Here you will have to provide the identifier name that you set in the Interface builder.
Your problem is that you have directly connected the button to push Segue to the B Controller. To stop navigating to B when condition is false, follow these steps :
Delete the current Segue from A to B.
Now Connect a segue from the ViewController button of the View in your storyboard to the B Controller. Look out for this yellow button below your A ViewController. See that yellow button at the bottom image. Connect a segue by dragging from that button to your B ViewController.
Now name that Segue with the name you gave before i.e loginSegue and try running your project. Now it won't go to B if condition is false.
Hope this helps.
No need to use prepareForSegue every time.
You can also push view controller by this code.
if( go == YES )
{
// navigate to B
UIStoryboard *story = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
viewController *viewObj = [story instantiateViewControllerWithIdentifier:#"viewController"];
[self.navigationController pushViewController:viewObj animated:YES];
}
else
{
// don't navigate to B
}
For this you have to give storyboardID to viewcontroller as "viewController" in your storyboard.
I am connecting three different views to one view and I am trying to create a back button that goes back to the view that I came from.
Example:
View A, B and C are connected to view D. I want to create a back button that goes back to say B, if I went to D from B. If I went to D from C, I want that button to go back to C and so on. How do I do this programmatically?
Here's some code:
On the sender we are using
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"SegueA"]) {
ViewController *destViewController = segue.destinationViewController;
destViewController.segueName = #"SegueA";
}
}
On the receiver side, we are using the following code :
- (IBAction)backBtn:(id)sender {
if([_segueName isEqualToString: #"SegueA"]){
[self performSegueWithIdentifier: #"SegueAA" sender:self];
}
So we are using a segue to go from A to D and then, if SegueA is identified we want to return via a segue from D to A called SegueAA.
Assuming you have UIViewController instead of UIView, you can use
[self.navigationController popViewControllerAnimated:YES]
You need to make a manual segue. You do this by making a segue from one view to another and then giving it a name in the interface builder.
Control Drag from one view to another
Under the "manual" segue type you probably want to use push
Click on the segue and go to properties and give it a name under the "Identifier" field
Then you can call it like so:
[self performSegueWithIdentifier:#"initalLegalSegue" sender:self];
(this block for example would launch my "initialLegalSegue" manually by code.)
With modal segues, I've been using this:
This goes back one view controller:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
This goes back two view controllers:
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];