I have 4 ViewControllers. Three of those view controllers are connected to the fourth one, which I call Photo_Detail. The segues there work fine, but now I have to make the back button go to the VC that someone came from. How can I do that? A research said to create a unwind segue in the Photo_detail, what i did but it didn't work out. That's the code I tried to use:
- (IBAction)done:(UIStoryboardSegue *)segue {
NSLog(#"Popping back to this view controller!");
// reset UI elements etc here
}
Thanks for any help in advance!
- (IBAction)done:(UIStoryboardSegue *)segue {
NSLog(#"Popping back to this view controller!");
// reset UI elements etc here
[self dismissViewControllerAnimated:NO completion:nil];
}
For Modal type segues, this will help you to move back.
And also select it as normal action from ViewController rather then exit. That will fix it.
Hope this helps.
If the second VC is presented modally, you simply have to dismiss the controller
[self dismissViewControllerAnimated:NO completion:nil]:
Related
I am trying to segue back to another UIViewController after modally presenting a UINavigationController and with it a root ViewController. What I want to happen is for a button to unwind from the root VC of the UINavigationController and return to the initial UIViewController that presented it. I have the unwind method written in the destination VC and button is hooked up to the Exit point of the VC. But when I press the button, nothing happens. Can someone explain what I am doing wrong? Any advice is appreciated.
Storyboard:
Storyboard
Code:
-(IBAction)unwindToClockView:(UIStoryboardSegue*)sender;
{
NSLog(#"Back to Clock View");
}
Additional code can be found here: https://github.com/xinkecf35/TrafficAlarmClock
Okay, I have a solution. It just involves programmatically calling a method trigger by the button that outright dismisses the view controller. The method is below.
-(IBAction)dismissSettings:(id)sender
{
[self dismissViewControllerAnimated:TRUE completion:nil];
}
If anyone can present a solution that uses Storyboards as well, it will be greatly appreciated.
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 a simple app with 2 screens.
When I press a button to go from the first to the second, everything is performed successfully (including animation). However, when I click the back button on the second screen, I get the following warning:
Warning: Attempt to present <getTextViewController: 0x8f6aa30> on <SecondViewController: 0x946cc80> whose view is not in the window hierarchy!
EDIT: Please don't refer me to other questions regarding above warning - I already saw those, and they refer to other issues.
However, it still switches back to the first screen. Yet, the animation of the segue does not perform.
Also: Information (such as inputted text) in the first screen remains when I return to the first screen, while information in the second screen resets every time the screen comes up.
Here is how I call both operations:
Segue from View 1 to View 2:
Name: F21, Style: Modal, Transition: Cross Dissolve, Animation: True.
Segue from View 2 to View 1:
Name: F12, Style: Modal, Transition: Cross Dissolve, Animation: True.
Code in getTextViewController.m (View 1):
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"F21"]){
UIViewController *v = [segue destinationViewController];
[self dismissViewControllerAnimated:NO completion:nil];
v = self;
}
}
-(void)performSegue:(NSString*)str{
[self performSegueWithIdentifier:str sender:self];
}
//In some other method:
[self performSegue:#"F21"];
Code in SecondViewController.m (View 2):
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"F12"]){
UIViewController *v = [segue destinationViewController];
[self dismissViewControllerAnimated:NO completion:nil];
v = self;
}
}
-(void)performSegue:(NSString*)str{
[self performSegueWithIdentifier:str sender:self];
}
- (IBAction)goBack:(id)sender {
[self performSegue:#"F12"];
}
I would very much appreciate any help to understand why the first segue works while the second doesn't.
Thank you,
Dean
NOTE: Here is the full project - https://github.com/dean13-meet/firstIOSApp
EDIT: Updated git.
Im not exactly sure what you're trying to do in your prepareForSegue, their is no need to be dismissing VC's there. If you want to have a simple app where you go from VC1 to VC2 and then back again, your best bet is to use a segue and an unwindSegue.
So in your storyboard control drag from a button on VC1 to VC2 and select your segue type. Then in VC1.m setup the unwind segue such as:
- (IBAction)unwindFromViewController:(UIStoryboardSegue *)segue
{
//empty implementation
}
Finally, in your VC2 control drag from the back button to the green exit icon on VC2 and select your unwindFromViewController method.
That should do what you're looking for.
For the sake of simplicity, I would suggest using a push segue opposed to modal because it takes care of all the back buttons for you. If you don't like the idea of a navigation controller however, try dismissing the view with the following: Moving back from a Controller to a previous one
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];
I have an iOS app that has a log in view (LognnViewController) and once a user is successfully authenticated they are taken to another view (DetailEntryViewController) to enter some simple details.
Once the details are entered the user is taken to the main part of the app that consists of a tab controller (TabViewController) that holds a variety of other views. The LogInViewController performs a modal segue to the DetailEntryViewController and the DetailEntryViewController then performs a modal segue to the TabViewController so I have kind of a modal segue chain going to get into the app. When a user logs out I want to go all the way back to the LogInViewController but when I do a:
[self.presentingViewController dismissModalViewControllerAnimated:YES];
...it pops the TabViewController and I end up back at the DetailEntryViewController instead of the first LogInViewController. Is there any way I can pop back to the first view controller easily or does doing this modal segue chain thing prevent me from that. I got the bright idea to put some code in the DetailEntryViewController viewWillAppear: that would automagically pop itself if the user had logged out but apparent making calls to dismiss a modal controller are not allowed in viewWillAppear: viewDidLoad:, etc.
Any ideas on how to make this happen?
I think this is not the best structure to implement your app. Modal controllers are supposed to be for temporary interruptions to the flow of the program, so using a modal to get to your main content is not ideal. The way I would do this is to make your tab bar controller the root view controller of the window, and then in the first tab's controller, present the login controller modally from the viewDidAppear method, so it will appear right away (you will briefly see the first tab's view unless you uncheck the "animates" box in the segue's attributes inspector). Present the details controller from that one, and then dismiss both modal controllers to get back to your main content. When the user logs out, just present that login controller again. I implement this idea like this. In the first tab's view controller:
- (void)viewDidLoad {
[super viewDidLoad];
_appStarting = YES;
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (_appStarting) {
[self performSegueWithIdentifier:#"Login" sender:self];
_appStarting = NO;
}
}
Then in the last (second in your case) modal view controller, I have a button method:
-(IBAction)goBackToMain:(id)sender {
[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
}
Figured it out myself...just had to go up one more level to get to the "root" view controller (LogInViewController) and found that this did the trick:
[[self.presentingViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil];
As I said I'm just getting the presentingViewController (DetailEntryViewController) and then going up one more level and getting that controller's presenter (LogInViewController).
I had similar problem and my "modal segue chain" was not limited. I agree with the arguments in the answer and comments below about modal segues designed for different thing, but I liked the "horizontal flip" animation of modal segues and I couldn't find the easier way to replicate them... Also in general I don't see anything wrong in using things that were designed for one thing to achieve some other thing, like chaining modal controllers. Repeated "partial curl" animation can also apply to some scenario in some app.
So I implemented the stack of modal controllers as a property of controller:
#interface ModalViewController : UIViewController
#property (nonatomic, retain) NSMutableArray *modalControllers;
#end
When the first modal segue is executed the stack is created in prepareForSegue method of controller that is not modal:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"modalSegue"]) {
ModalViewController *controller =
(ModalViewController *)[segue destinationViewController];
controller.modalControllers = [NSMutableArray arrayWithObject: controller];
}
}
When one modal controller moves to another the destination is added to the stack (in the method of ModalViewCotroller)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"modalSegue"]) {
ModalViewController *destController =
(ModalViewController *)[segue destinationViewController];
// add destination controller to stack
destController.modalControllers = _modalControllers;
[destController.modalControllers addObject: destController];
}
}
To dismiss the whole stack at once was the most tricky part - you can't dismiss the previous controller before the next finished dismissing, so the cycle did not work, only recursive blocks did the trick, with avoiding the memory leak being the trickiest (I'm yet to check it, but I relied on this):
- (IBAction)dismissAllModalControllers: (id)sender
{
// recursive block that dismisses one auth controller
// all these dances are to avoid leaks with ARC
typedef void (^voidBlockType)();
__block void (^dismissController) ();
voidBlockType __weak dismissCopy = ^void(void) {
dismissController();
};
dismissController = ^void(void) {
int count = [_modalControllers count];
if (count > 0) {
// get last controller
UIViewController *controller =
(UIViewController *)[_modalControllers lastObject];
// remove last controller
[_modalControllers removeLastObject];
// dismiss last controller
[controller
// the first controller in chain is dismissed with animation
dismissViewControllerAnimated: count == 1 ? YES : NO
// on completion call the block that calls this block recursively
completion: dismissCopy];
}
};
// this call dismisses all modal controllers
dismissController();
}
[self.navigationController popToRootViewControllerAnimated:YES];