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

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.

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.

How to navigate in iOS application

I have a screen in my application (login), that may be presented from any other screen
i want to put the logic of starting that screen outside of my ViewControllers, so it is not duplicated
is this possible ?
this screen may also be loaded upon an NSNotificationCenter notification message that i received
So, I'd put this into a controller where each of the view controllers calls this controller to perform the login. When the login is requested, pass the requesting view controller (or its parent if it isn't full screen) as a parameter.
Now, when the login view needs to be presented you have a generic way of presenting it from inside the 'login controller'. The requesting view controllers know nothing about the 'login controller' and the 'login controller' knows nothing about the requesting view controllers.
When triggered by a notification the app delegate can get the root view controller from the app window and pass that as the requesting view controller.
You can just create a ViewController for your login screen and give it a "storyboard id" under the "Identity inspector".
And when you'd want to show it you can instantiate it like this:
loginViewController = [[self storyboard] instantiateViewControllerWithIdentifier:#"storyboardID"];
after that you can either push it if you are using a navigationController or add it as a subview.
EDIT: how do i know if it is present:
NSArray *controllers = self.navigationController.viewControllers;
for (UIViewController* controller in controllers)
{
if ([controllers isKindOfClass:[LoginController class]])
{
NSLog(#"is already present");
}
}

Circular application flow - Need Idea

I have an screen (My Profile) which can be accessed from two paths:
Login -> Content -> Profile
Login -> Register -> Profile.
In both paths, view's are shown with:
[self.navigationController pushViewController...];
But my problem is, after the user registers and completes his profile, it should go "Back" to the Content view. (Obviously it won't work with navigation controller stack, since Content isn't in the navigation controller).
My question is, what suggestions do you have?
PS: I know this isn't an actual question, but I've been thinking about this for a few hours now and I didn't come up with anything. Maybe some of you have had to deal with similar cases.
Edit: Basically the question can be generalised to:
How do you deal with a circular application flow?
Edit: I've solved this by pushing from Register to Content and then Profile in viewWillAppeare without animation (so what I need is in the stack), but I'm still interested in dealing with circular application flows.
My suggestion would by to change [UINavigationController viewControllers].
So after you end your registration you can do something like
ContentVC *content = [[ContentVC alloc] init];
[self.navigationController setViewControllers:[NSArray arrayWithObject:content]];
[self.navigationController popToRootViewControllerAnimated:YES];
Push Contentview controller after profile complated in second case , while in first case you have already pushing it.
1)Make your Login viewController the rootController of the a UINavigationController.
2)From Login you can Push Content ViewController
3)From Content VC you can push to Profile VC.
Now if you want to get back to Content from profile do this:
[self.navigationController popViewControllerAnimated:YES];
And if you want o get back from Profile directly to Login do this:
[self.navigationController popToRootViewControllerAnimated:YES];
If you do not want the navigation bar you can hide the bar.
Update
Take a different approach, other than the navigation controller stack:
1) Make a controller class with a 2 functions:
-(void)loadViewControllerWithIndex:(int)index;
and
-(void)unLoadCurentViewController;
2) You can call these functions and load and unload the view controllers from a this controller class.
3) So you initially load this class and import file in this class of other view controllers. You can take a UIViewController object topViewController, so that you can you can keep a track on which controller is currently displayed and it will help when you want to unload a controller.
4) In load controller with Index function you can add the controller view and in unload you may remove them.

CollectionView -> changing flow based on if logged in

I have an App using a Story Board, CollectionViews and a NavigationController setup. This works fine, but now I want to add in login.
So if the user is already logged in, I want to bypass the default behavior of going to the login screen.
What is the best way to change this flow?
thanks!
phil
Put logic in the viewDidAppear method of the navigation controller's root view controller that determines whether to show the login view or not. Present it modally with the animation set to no, and it will be the first thing the user sees.
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (!self.loggedIn) {
UIViewController *login = [self.storyboard instantiateViewControllerWithIdentifier:#"Login"];
[self presentViewController:login animated:NO completion:nil];
}
}
You can either tell the regular first view controller to instigate the segue in code when it appears (e.g. login view says: show next view if logged in).
Or something more radical in your app delegate, but I think it is safer to leave the flow as it is and just make it move on to the next screen and leave your storyboard untouched.

How to remove UINavigationController first view in stack after used?

I have a UINavigationController which has a loginview that appears once the app has loaded.
Once the user clicks Login, we push the next view onto the stack and it appears. I want the user to not be able to go back to the loginview.
How do I remove the loginview from the stack after the next view is loaded?
Note: It is a requirement that the only container of the app is a UINavigationController.
You can use setViewControllers:animated: to modify the controller stack, but I'd encourage you to reconsider whether you really want your login view controller to be the root of your navigation stack. When users see a navigation controller, they expect to be navigating up and down a hierarchy of screens organized in a tree structure. Changing the root of that tree undermines the metaphor somewhat.
Consider using modal presentation to communicate the the fact that the login experience falls outside of your app's main hierarchical navigation structure. Here are a couple options:
A. Start on login view controller, and present the navigation controller modally.
If your login view controller is always going to be the first screen the user sees, you could add its view directly to the window without the navigation controller. Then once the user logs in, create the navigation controller and present it by calling presentModalViewController:animated: from your login view controller.
B. Initialize the navigation controller with its true root, and present the login view controller modally.
This option may be worth considering if the login prompt isn't always the first view the user sees, especially if the login prompt can pop up in other contexts. For example, I used this approach in an app that allows the user to access some sections while offline or anonymous. The login prompt gets presented modally when the user tries to access content requiring authentication.
Remove the back button, by setting the backButtonItem, on the navigationItem of the login controller, to nil.
In above case your loginview Controller will be called root controller for your UINavigationController
Read below How to remove Root controller of UINavigationController
http://starterstep.wordpress.com/2009/03/05/changing-a-uinavigationcontroller%E2%80%99s-root-view-controller/
I found that by just setting the ViewControllers property, that would do the trick.
(We use C# and .NET to build iPhone apps with MonoTouch)
public override void ViewDidAppear (bool animated)
{
NavigationController.ViewControllers = new UIViewController[] { this };
}
use NSUserdefault to set bool check value to verify to show login page or next page
for example while login page u will get username password then send it to server and u will recieve the result as success or fail
if success then set the Bool in NSuserdefault to yes
and push nextview after successfully login.
if next time user come to ur app u have to first check out NSuserdefault for that bool value
according to that u can push nextviewcontroller or login page.
that's it.
in nsuserdefault u can specify string for key instead of bool
after succesfull login
set isLogined to yes
NSUserDefaults *std = [NSUserDefaults standardUserDefaults];
[std setObject:#"yes" forKey:#"isLogined"];
if not set NO
in before push login page just verify if the isLogined yes or no
according to that u can push login page or nextpage
to verify
[std stringforkey:#"isLogined"];

Resources