Perform segue to a view that may not have been created - ios

I have an app with 4 views, CheckAuthenticationView, HomeView, LoginView and DetailsView.
When the user starts the app the first view loaded is CheckAuthenticationView. This view checks the keychain for login information and if it exists, attempts to log the user in automatically and if successful, segues to DetailsView. If no information exists it performs a segue to the HomeView from which a user can then proceed to login.
Now on the DetailsView I have a button so the user can log out. If tapped, this clears any login information and performs an unwind (exit) segue to HomeView.
If a user does not logout but kills the app (restart phone etc), CheckAuthenticationView should produce a successful result meaning DetailsView will be loaded automatically. If this is the case, when I tap logout, the segue does not fire and the user remains on the DetailsView.
I am guessing that the segue does not happen because HomeView has not actually been created so there is nothing to segue to. Is there a way to segue to a view that has not yet been created?
Thanks

What do you mean by not yet created? If you haven't created the ViewController or any sort of view in your storyboard, then no you cannot segue to a view that does not exist. If you have created it then you can just call:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
UIViewController *homeView = [storyboard instantiateViewControllerWithIdentifier:#"HomeView"];
[self presentViewController:vc animated:YES(or NO) completion:nil];

Related

Creating a central log out view controller in storyboard

I am working with Parse, and one thing I have implemented in my app is their built in PFLogInViewController. This controller will be presented at two times in the application - when the app first starts and the user is not logged in, and when the user taps the "Log out" button of my application (logging out takes them back to the PFLogInViewController, as you are required to sign in to use the app). I would like to set this up using Storyboard, as that is how the rest of my app is laid out. How could I set up a central view controller (a PFLogInViewController) that is accessed at these two times? I have already Subclassed PFLogInViewController and set it up, I just need advice on how to place it in Storyboard and how to connect it to my views. To make this question help as many people as possible, the general theme of my question is how does one establish a central Login/ViewController that can be accessed at different points in the application using Storyboard. Attached is the basic idea of what I'm trying to accomplish. I haven't been able to successfully segue to the initial TabBarController, and I'm not sure how I should make the LoginController the initial ViewController if I can't segue. I am programming in Swift, if it matters.
There are a few ways to do this depending upon your application. One way is drop a UIViewController onto the storyboard, but don't wire it up to anything (no segue). Create a storyboard id for it such as "MyLoginVC". Do the necessary subclassing of UIViewController and attach the class to your VC. Then, when you want to display the VC simply do the following or wire this up to your logout button
id destinationVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MyLoginVC"];
[self.navigationController pushViewController:destinationVC animated:YES];
In addition, if you want to show the login VC as the very first VC when you launch your app, then perhaps in your AppDelegate
// Load Root view controller
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.rootVC = [storyboard instantiateInitialViewController];
self.window.rootViewController = _rootVC;
[self.window makeKeyAndVisible];
// Load Login view controller
id initialVC = [storyboard instantiateViewControllerWithIdentifier:#"MyLoginVC"];
[initialVC setModalPresentationStyle:UIModalPresentationFullScreen];
[_rootVC presentModalViewController:initialVC animated:NO];
When you finish with your login VC (i.e. successful login) then within login VC
[self dismissViewControllerAnimated:NO completion:nil];
and alternatively instantiate your first VC with something similar to the following from within login VC. Note, since you loaded the root VC above first, it is already there with the login VC sitting over it. When you dismiss login VC, the underlying root VC should be ready to rock and roll. Otherwise you can do the following:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
RootTabBarController *tbController = (RootTabBarController *)[self.storyboard instantiateViewControllerWithIdentifier:#"rootTabBarController"];
[self presentViewController:tbController animated:YES completion:NULL];
}
I think what you want is an unwind segue. Here are the instructions I follow for an unwind segue: https://github.com/bradley/iOSUnwindSegueProgramatically
If the link dies, here is what it said:
In your storyboard create two view controllers.
Subclass UIViewController twice, once for each of the view controllers in your storyboard.
Connect these view controllers to the view controllers in your storyboard.
Make a segue between the first view controller and the second by control+dragging from the first to the second.
Click on the segue you created and give it an identifier in the attributes inspector.
Make a button on the first view controller and link it to an IBAction in its UIViewController subclass.
When this button is pressed, the second storyboard should appear. To make this happen (we are doing it programatically) put the following into the implementation of the action you just created:
[self performSegueWithIdentifier:#"nameOfTheSegueBetweenOneAndTwo" sender:self];
Create a second method in the implemention of the first view controller with the following:
- (IBAction)returnToStepOne:(UIStoryboardSegue *)segue {
NSLog(#"And now we are back.");
}
This method will work to unwind any view controller back to this view controller. Notice that we implement the method in the view controller we wish to return to.
Go back to the storyboard. Focus in on the second view controller. If it is active, you should see a dark bar beneath it with 3 symbols on it. One of these is orange and when hovered over will show the name of the UIViewController subclass that this view controller represents. Control drag from this symbol woth the green symbol that means 'Exit'. You should see all available segue unwinds, which XCode automatically enumerates when you create segue unwind implementations inside UIViewController subclasses that you have shown on your stroryboard. Hence, you should see the segue 'returnToStepOne' as an option. Select it.
In your storyboard's document outline, find the section for the second view controller. You should see an item listed below it with a grey symbol that says something like "Unwind segue from ... to Exit." Click on this item.
Important and easily missed step follows!
On the right side of your storyboard, in the attributes inspector, you should see two fields. One for 'Identifier' and one for 'Action'. In most cases, the 'Action' field will have the text 'returnToStepOne:', which is what we want, but the 'Identifier' field will be blank. Fill this field with the text: 'returnToStepOne' (note that we leave out the colon).
Create a button on the second view controller and link it to an IBAction in its UIViewController subclass.
In the implementation for the method you just created, put the following code:
[self performSegueWithIdentifier:#"returnToStepOne" sender:self];
Run the application. You should now be able to unwind from the second view controller to the first.

Pop to rootViewController and then load a new viewController

I have a login screen(embeded in navigation controller) with 2 buttons: "Register" & "Login".
When the user press register and has successfully registered I want to to load the Login controller.
What I have in mind:
1) Draw a segue from RegisterVC to LoginVC and by pass the rootVC. This is not seems right to me
2)Save a property in NSDefaults then poptoNVC from register and have the viewWillAppear to check if it will executed the segue to LoginVC automatically.This is also does not seems to me right.
Is there any way to get a pointer to rootVC from RegisterVC executed the poptoNVC and as soon as poptoNVC is finished use the pointer to execute a segue to login?
Do you have any suggestions?
I suggest you to open the register view controller with
presentViewController (or use segue) type modal instead push the viewController.
When you dismiss the registerViewController, use:
[self dismissViewControllerAnimated:YES completion:^{
[_delegate goToLogin];
}];
so basically you can use the delegation pattern to say to the rootViewController (that is the delegate) that the registerViewController is dismissed and can access to the loginViewController.
OR: You can use your check in viewWillAppear but is not elegant for me.

Redirect to a specific view controller

Just Have an issue and a "miss" in my programming "capacity".
I've got a tableview controller with some data parsed from a json.
When you choose a "news" you to to the detail view with all data in it.
Everything is ok, but I add a "check" If you are logged or not.
And if not you are "redirected" to login screen.
I try to do it with a segue (modal). It's working, but when I do it, my "navigation" is broken, like if he "lost" he's path.
I try to do it programatically like :
LoginViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
[self.navigationController pushViewController:controller animated:YES];
But when I'm doing it like that, nothing happen, my "detail view controller" load without redirecting
and got that log:
nested push animation can result in corrupted navigation bar Finishing
up a navigation transition in an unexpected state. Navigation Bar
subview tree might get corrupted.
Did someone have a hint for me ?
Thanks
you are doing it all wrong. you need to study the very basic of seque programming (storyboard).
follow this link
LoginViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
[self.navigationController pushViewController:controller animated:YES];
in storyboard you already have a push segue, & again you are pushing loginviewcontroller. thats why you are getting "nested push animation" warning.
This isn't the normal way to do it. You would normally present that login view controller modally.
If this is just the way you want it you could do it using the following steps:
1) Connect your DetailViewController to your TableViewController (not from cell itself, but from that yellow icon which represents your ViewController at the bottom black bar). Choose push if you like and add the identifier to that Segue (for example, "DetailSegue")
2) Connect your LoginViewController to your TableViewController just like you connected your DetailViewController and add the identifier to that segue (for example, "LoginSegue").
Now, when the user clicks on some cell, you wish to check if session is still active, if it is you will do [self performSegueWithIdentifier:#"DetailSegue" sender:self];, and if it is not, you will do [self performSegueWithIdentifier:#"LoginSegue" sender:self];
Hope this helps, cheers.
it's pretty tough to understand what you want to do, the question isn't too clear.
If you want to link to a scene in your storyboard though, create a segue to this by ctrl + click & drag from the initial scene, then give the segue an ID (do this by clicking on the segue and using inspector to set an ID)
then in your tableview controller, where ever you are picking up your tab (assuming this is in the tableview delegate method) you can call the segue programatically
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"YOURSEGUEID" sender:self];
}

Keep text in text field persistent, even when switching view controllers

I would like to be able keep the text in a textfield persistent as I switch between view controllers.
I'm making a login screen and the login. However, if I go back to the login view controller after being in another view controller, the login information disappears (I'm pretty sure it's because it's a new instance of the view controller).
What I want to happen is that if a user enters in their login information and then goes back to the login view controller, they don't have to retype their info in.
Edit: Here is code for my programmatic segue to switch view controllers:
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"secondViewController"];
secondViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:secondViewController animated:YES completion:nil];
NSLog(#"Login SUCCESS");
Embed your first controller in a navigation bar. Next take out that code and use:
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"secondViewController"];
[self.navigationController pushViewController:secondViewController animated:YES];
If you want this to persist across launches of the program, then you should store the login information whenever they change it, and then read it back in whenever your login view controller loads and set the text field values from that.
You can store the information in a couple of different ways:
iOS Keychain
See this SO question for an example of how to store information securely in the keychain:
iOS: How to store username/password within an app?
NSUserDefaults
If you are only storing the username (and not the password) then you could use NSUserDefaults.
See this question for a good example:
Save string to the NSUserDefaults?
If the login controller is the first controller, the window's root view controller, it won't be deallocated unless you change which controller is the root. This doesn't happen when you're presenting and dismissing modal view controllers. I'm guessing that you're going from SecondViewController "back" to login controller by doing another modal presentation. Is that what you're doing? If so, that's wrong, that does create a new instance of login controller as you suspected. Instead, you should dismiss SecondViewController when you want to go back to the login controller. You need to do this in code rather than using a segue in the storyboard.

iOS - Log out of app

I have an app that starts out in the login screen and when you log in it pushes a modal TabBarController. One of the tabs is settings which has a logout button, what would be the correct way to log out of my app and not have any issues such as memory leaks?
It really depends on how your users are logging in. What you probably need to do is the opposite of whatever you are doing to login. If all the login does is open the modal dialog, then closing it should be fine. It you are setting some kind of security token, then you will need to set it to nil.
Without knowing more about how your app works, there isn't much more I can say.
I know this is old, but if you want to present your login screen (because you logged out) as a modal, you can do this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
//Your login view controller, make sure you set the storyboard id
TTTLoginController *log = (TTTLoginController *)[storyboard instantiateViewControllerWithIdentifier:#"log"];
//wrap it in a navigation controller
UINavigationController *navBar=[[UINavigationController alloc]initWithRootViewController:log];
//present the modal view
[self.navigationController presentViewController:navBar animated:YES completion:nil];

Resources