I create one application that has 3 ViewController with names : (ViewController,ViewController2,ViewController3)
in ViewController exist one button that is for checking file in document folder or download it.for example first to check file if file exist in document folder go to ViewController3 else go to ViewController2 and download it.
so ViewController2 is for download and has UILable & UIProgress for show download status.if file dont exist in this page downloaded and go to ViewController3.
so ViewController3 is for show file.
(these pages connect together with push segue like my image in bottom)
when I go to any page and I click back button return pervious page right??
I when to click on button in first page and file dont exist and downloading in second page then finished download go to page 3.Now I want when to click on back button in page 3 go to page 1 no page 2!!!!
I to work in storyboard.
You can achieve this by intercepting the back button event in ViewController3 and using unwindSegues.
Check out William Jockusch's reply to this question for how to intercept the back button event.
To use the unwind segues in this particular case you then need to:
1) In your ViewController1 create a method such as
- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue
{
NSLog(#"Rolled back");
}
2) In your storyboard zoom out, then ctrl-drag from your ViewController3 to the "Exit" green box on the left contained in your ViewController3 scene (along with the red box First Responder and all your controller view's subviews). A popup window will show, asking what IBAction you want to connect the unwind segue to, and you should be able to select the unwindToThisViewController action that you just created. This will create an unwind segue.
3) Select from the scene box this unwind segue and give it an ID, such as "unwindToStart"
4) Finally, in your ViewController3 class, override the method viewWillDisappear as follows:
-(void) viewWillDisappear:(BOOL)animated
{
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
[self performSegueWithIdentifier:#"unwindToStart" sender:self];
[super viewWillDisappear:animated];
}
This will intercept the back button event and unroll to your ViewController1, and you're good to go.
EDIT: As unwind segues are supported only on iOS 6 and later, if you need this functionality on earlier versions of iOS I think the only way is to manually remove the ViewController2 from the NavigationController stack in your ViewController3's viewDidLoad. Something like the following code should do:
- (void)viewDidLoad
{
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
for(UIViewController* vc in self.navigationController.viewControllers)
{
if ([vc isKindOfClass:[ViewController2 class]]) {
[viewControllers removeObject:vc];
break;
}
}
self.navigationController.viewControllers = [NSArray arrayWithArray:viewControllers];
// Do any additional setup after loading the view.
}
Related
Here is the problem
1) Rootview controller - MYAssetVC-> Embedded with NavigationController here pushing for button to another Addfilevc.
2) Addfilevc Has dropdownTextfield It will push to another vc have tableview selected row will display in the textfield.
3)if i select another value from the dropdown textfield it will push to the vc again there i will select.
Navigation bar back button will navigate to all my view hierarchy i want to handle this one. if i go to same view it should navigate back only once that to the recent visit how to do this.
As i am new to iOS. give any suggestion.
Navigation from 1->2->3
navigation backbtn 3->2->1
if i navigate like this 1->2->3-> backbutton 3->2 again 2->3 backbutton 3->2 again 2->3
IF i navigate now using back it is displaying all my route path it should navigate like 1->2->3> and 3->2->1 if any number of times i perform actions in 2 & 3.
1,2,3 are view controllers.
Create an IBAction for the back button and use popViewController.
[self.navigationController popViewControllerAnimated:YES];
This will help you to go back one page. You have to write this in all the pages where there is a back button and you want to go back one page.
If you want to go back directly to rootViewController, try this:
[self.navigationController popToRootViewControllerAnimated:YES];
And if you want to pop to any specific viewController in the stack, you run a for loop to find the viewController you want to navigate to and then simply popToViewController, like this:
for (UIViewController *viewController in self.navigationController.viewControllers) {
if ([viewController isKindOfClass:[Addfilevc class]]) {
[self.navigationController popToViewController:viewController animated:YES];
}
}
Hope this helps to clear your concept.
EDIT
In swift:
The [self.navigationController popViewControllerAnimated:YES]; will become self.navigationController?.popViewControllerAnimated(true)
The [self.navigationController popToRootViewControllerAnimated:YES]; will become navigationController?.popToRootViewControllerAnimated(true)
And the for loop will be as below:
You can use this if you are using storyboard
let switchViewController = self.storyboard?.instantiateViewControllerWithIdentifier("view2") as ComposeViewController
self.navigationController?.pushViewController(switchViewController, animated: true)
And the for-in loop
if let viewControllers = self.navigationController?.viewControllers {
for viewController in viewControllers {
self.navigationController!.popToViewController(viewController, animated: true);
}
}
Thanks.
I want to perform some code when the segue goes back one step. For example, when the back button gets selected, I want to perform some code.
I can't create a new unwind action from the back button because there is no back button in the storyboard. Is there a way to insert code, as soon as the back button is selected?
If you want to stick with the default back button, one way to do this is to subclass the navigation controller, and override popViewControllerAnimated: which is called when you tap the back button.
-(UIViewController *)popViewControllerAnimated:(BOOL)animated {
UIViewController *vcToBePopped =[super popViewControllerAnimated:animated];
id vc = self.viewControllers.lastObject; // this will be the controller you're going back to
if ([vc isKindOfClass:IntendedViewController class]) { // replace IntendedViewController with the actual class name you care about
[(IntendedViewController *)vc someMethod];
}
return vcToBePopped;
}
I am fairly new to navigation view controllers and stacks in iOS. Please help me with this, tried searching for a long time couldn't find anything relevant.
I have a LoginViewController, a SWRevealViewController for side menu operation, a FirstViewController (the first one in navigation stack) and a SecondViewController (second in navigation stack).
I have to do the following in LoginViewController, assume login and found are two boolean variables:
if (login && !found) {
//redirect to FirstViewController : the following works
[self presentViewController:swReveal animated:NO completion:nil];
}
else if (login && found) {
//redirect to SecondViewController
}
Please help me fill the else if. Really appreciate your time!
So based on what I understood from your comments, FirstViewController is a subclass of TableViewController and SecondViewController is the DetailView.
So based on that, the best approach for "redirecting" to the DetailView (SecondViewController), would be creating a segue on the Storyboard, and then calling that segue programatically once the FirstViewController is loaded (in its viewDidLoad)
On both cases you would first show the FirstViewController and then depending on the if statement, you would either stay or go to the SecondViewController.
So first step: Create the segue from the Storyboard, and give it an identifier.
Second: Perform that segue programatically when the FirstViewController is loaded (and of course, the if statement is valid) by using:
[self performSegueWithIdentifier: #"MySegue" sender: self];
More on that subject:
Alternative ways to push view controllers with storyboard programmatically
Creating a segue programmatically
I have the following storyboard in an application I am working on:
At the root, I have a Tab Bar Controller. It links to two View Controllers.
The first View Controller to display a newsfeed with pictures uploaded by the user (the one at the bottom in the storyboard).
The second View Controller serves to initiate the taking of a picture and attach some data to it. In the last step (top right), when touching "Save" in the right item of the Navigation bar, I want the user to be redirected to the newsfeed View Controller passing it some data.
I tried using a segue and it works. The data are passed to the newsfeed but the wrong tab is selected. I changed the selected tab using
[self.tabBarController setSelectedIndex:0];
But by tapping on the second tab again, things are messed up. I can see the newsfeed instead of the taking a picture screen. If I tap again, it crashes.
At some point I thought I may have got the wrong storyboard and should have implemented a TabBar in my newsfeed and handle the taking picture as a modal view.
Would you know any clean way to achieve this?
Thanks
You should not use a normal segue, which adds the destination controller to the stack. To do what you are trying to the best way should be to use an unwind segue. This is a rough sketch of what you need to do:
• Declare an unwind segue action in the NewsfeedController like (IBAction)unwindFromPictureSaved:(UIStoryboardSegue *)segue;
• Connect your "Save" button in your SavingPictureController to the "Exit" icon in the storyboard and select the previously defined method;
• In the newly created unwind segue define its identifier with something like SavedPictureSegue;
• Define the data to be passed in SavingPictureController's header with something like #property (strong, readonly, nonatomic) id passedData;
• In SavingPictureController implement
-(void)prepareForSegue:(UIStoryboardSegue *)segue
{
if ([segue.identifier isEqualToString:#"SavedPictureSegue"]) {
_passedData = // Your data here
}
}
• In NewsfeedController now implement the previously defined method and fetch the data from (SavingPictureController *)segue.sourceController. Be sure to #import "SavingPictureController.h".
Thanks to #Davide, I created a subclass of TabBarController and implemented the method below:
// Find the appropriate controller to answer to an unwind segue
// For each child view controller
// Checks if it is a Navigation Controller
// If it is check its children view controllers
// Return the first view controller that answers the unwind segue
// This because I assumed the default behavior is just to check one level up (in this case, it would have stopped at the NavigationController)
// Based on https://developer.apple.com/library/ios/technotes/tn2298/_index.html#//apple_ref/doc/uid/DTS40013591-CH1-CCVC-SELECTING_A_CHILD_VIEW_CONTROLLER_TO_HANDLE_AN_UNWIND_ACTION
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender {
BOOL resChildren, res;
for(UIViewController *controller in self.childViewControllers) {
if ([controller isKindOfClass:[UINavigationController class]]) {
for (UIViewController *childController in controller.childViewControllers) {
resChildren = [childController canPerformUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
if (resChildren) {
return childController;
}
}
}
res = [controller canPerformUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
if (res) {
return controller;
}
}
return nil;
}
Then in the unwind method of the 'NewsFeedController" it is necessary to set the correct index to see the controller with something like:
[self.tabBarController setSelectedIndex:1];
I uploaded a demo on github at https://github.com/kintso/unwindSegueWithTabBarControllerAndNavigationController
I connected first view controller with the second one using StoryBoard Push Segue and Interface Builder.
The button is named GO on top/right.
I have three textfield that must be filled before going to second controller.
I display an alert when one of them is empty.
The problem is that my code after displaying correct alertView goes to SecondController instead of remaining on mainController.
if ([segue.identifier isEqualToString:#"DataDisplay"])
{
if (![self verifySelection]) {
return;
} else {
RowViewController *rowViewController = segue.destinationViewController;
// rowViewController.delegate = self;
}
}
1) You have a segue wired directly from your Go button to your Sensor Data view controller. You don't want this, because anytime someone touches Go, the segue is going to happen ... no stopping it. So, first step is to remove the segue you have going from Go to your second view controller.
2) Instead, wire the segue from the File's Owner icon below the view controller to the second view controller. Give it a name like DataDisplay.
3) In the IBAction for your Go button
if ([self verifySelection) {
[self performSegueWithIdentifier:#"DataDisplay" sender:self]
}
An easy fix would be to create the segue manually, rather than letting the interface builder manage it. So you would ctrl-drag from your main view controller to your second one, selecting push as the type of segue and assigning it an identifier through the identifier inspector, then you connect an IBAction to your Go button and in the method you perform the checks on the text fields before programmatically firing the segue with:
[self performSegueWithIdentifier:#"whateverIdentifierYouGaveYourSegue" sender:self];
Heads up: to create a manual segue from a viewcontroller to another one, you need to either zoom out in your storyboard or ctrl-drag from the yellow circle underneath the view!
Edit: Your IBAction connected to the button method should be something like the following:
- (IBAction)download:(id)sender {
if(text boxes are ok)
[self performSegueWithIdentifier:#"segueIdentifier" sender:self];
else
[self showWarning];
}
Make sure that you assigned the ID segueIdentifier to the segue you created in your storyboard.
Your problem is you are defining the "performSegueWithIdentifier" after displaying the alert.
I think the code you are doing is like this :
//AlertView Allocation
[alert show];
Perform Segue
If this is how you are doing, then you are doing it wrong.
You have to use the structure of If-Else Statements and put up the Perform Segue in the condition where all the textfields are filled.