How to remove UINavigationController first view in stack after used? - ios

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"];

Related

SWrevealviewcontroller should be visible on welcome screen after login

I am new to iOS ran into a problem, I have successfully implemented SWRevealViewController side menu and it works if I put the view controller as initial screen but when it comes to showing it after login procedure it does not show up the menu, so after searching the web for quite some time I found out that I need to design a separate story board for login and register and separate for other screens.. so I did it as per that. Still, I have problems in showing up my side menu. My code does not get in
if revealViewController() != nil{ }
It returns NULL so the code does not go ahead.
And this is my second storyboard:
I am using UserDefaults to keep whether the user is logged in or not and storing user profile details in UserDefaults as well to be used within the app for future.
No need to use second storyboard.
You can simply switch between UIViewControllers by implementing a container view controller, if not using segues for specific reasons.
However, what I would suggest is to set your main view controller, revealViewController?, as an initial view controller, and check login status (using your UserDefaults) on viewDidLoad(). If there's no available login info, modally present another view controller for the login process. Then simply dismiss the login view controller if login succeeded.

Transitioning from login view controllers to the main page

I have a little app that I'm building and wanted some opinions on the way I'm implementing login. Here's my plan:
1) Open app
2) Load ContainerViewController (The container view controller will play a little animation that shows the app is doing some loading)
3) The ContainerViewController checks if a token exists in the keychain. If a token does exist, then check if its valid or not.
3a) If the token is valid, add HomeViewController (a view controller that is the root of a navigation controller that is basically the main page of the app) as a child view controller.
3b) If the token is invalid, add LoginViewController (a view controller that basically handles the signing in process) as a child view controller.
If you sign in successfully at the login page, loginviewcontroller will be removed as a child and homeviewcontroller will be added as a child.
Is using container and child view controllers the right way to go about handling the opening of the app? By the way, I'm building it completely programmatically, which means I'm not using storyboards so segues can't be used (unless I'm totally wrong there). Thanks guys
This is the right approach to implementing the login process. In short Up on login, you check for the token, if it is there and valid you present the MainViewController. Else you present the LoginViewController.
PS(Thumbs up for developing it programatically! I like that way as well)

Correct method to navigate (push/pop) between 3 different views in a UINavigationController

It has been some time since I have worked on an iOS project and am struggling with what is likely a fairly basic concept to do with UINavigationControllers.
I have the following setup in my storyboard:
Navigation Controller
View 1: Login View (Root)
View 2: Register View
View 3: Verification View
My project flow requires that, after a user registers an account in the Register View, they be taken to the Verification View. My project flow also requires that I show the Verification View if the user logs in from the Root View and they have not verified their email address.
It is important that if the user presses back in the Verification View that they are always taken to the Login (Root) view, never the register view.
I have reviewed the following questions:
Navigation Controller Push View Controller
UINavigationController pushViewController in viewDidLoad not working
As well as many others and not found a good rule of thumb for situations like this. I expect the best course of action would be to return from the Register View (Pop) to the Root view and then tell the Root view to move to the Verification View using a segue but [self parentViewController] in the Register view seems to give me the UINavigationController.
My question is this: What is the correct flow to use here?
In the login VC add unwind method:
- (IBAction)unwindFromVerification:(UIStoryboardSegue *)segue { }
In verification VC in storyboard ctrl+drag from VC object to the Exit and select the created method. Set the identifier for that unwind segue (e.g. "UnwindFromVerification"). Then in verification VC whenever you need to unwind you just call
[self performSegueWithIdentifier:#"UnwindFromVerification" sender:nil];
Then just set hidesBackButton to YES on verification view's navigationItem and replace it with your own. Another solution would be to hide the navigation bar altogether so that user wouldn't be able to unwind by swiping right from the left edge.
for your Q2
It is important that if the user presses back in the Verification View that they are always taken to the Login (Root) view, never the register view.
use popToRootViewControllerAnimated:YES it Navigate to Login VC
[self.navigationController popToRootViewControllerAnimated:YES];
for your another Question
My project flow also requires that I show the Verification View if the user logs in from the Root View and they have not verified their email address
Ans :
create the one bool userdefault in Login VC, check bool == false, directly navigate to Verify View, in that verify VC, if everything is fine set bool == true, else if user is new navigate to register view else navigate to main VC.

iOS Modal Login Screen presented anywhere in app

What is the best approach to create an iOS app login screen that slides in (by presenting it modally) whenever the user isn't logged in?
A user will be "logged out" in the following circumstances:
he has never logged into the app (i.e. first use)
he has explicitly logged out of the app
he is logged out on the server (e.g. his security token has expired
on the server, and that is communicated to the app)
My app consists of a UINavigationController that is set as the app's RootViewController, and each screen (other than the Login screen), is pushed onto the NavigationController as the user navigates the app. One of the screens a user can navigate to (i.e. that is pushed onto the stack) is the Logout screen (where the user can log out of the app). The Login screen should appear modally when needed, and the logic and presentation should happen from one centralized place. I am using Storyboards.
What I have tried is to subclass UINavigationController (for the RootViewController), and in its viewDidAppear method I check whether the user is logged in (I store a flag in NSUserDefaults). If he is logged in, the app's first screen is (programmatically) pushed onto the stack; if he isn't logged in, the Login screen is (programmatically) presented modally.
This approach has the following two issues:
you cannot set a background image for the subclassed
UINavigationController, so a blank screen appears for a short while
the subclassed UINavigationController's viewDidAppear is not
called when popping to its RootViewController (specifically when
popped from the Logout screen)
Ideally I want one central place to check whether a user is logged in (I was hoping the subclassed UINavigationController's viewDidAppear method would be this spot) to check the user's logged-in state, and present the modal Login screen if needed.
I have looked at Login Screen using Storyboard and Example for login screen modally based on storyboard (and others referenced in these) but none of them address the issue of presenting the modal Login screen from a central point.
First you should note, that as per Apples developer notes, you are not supposed to subclass UINavigationController.
Second, this is fairly opinion based, however I suggest you should use your application delegate class as the pillar point for checking login status, it's a singleton as UINavigationController, effectively is.
I would suggest posting an NSNotification that your AppDelegate can listen for so that the AppDelegate takes responsibility for presenting your modal login view.
Your communication layer can be responsible for posting the notification whenever the user logs out or the server responds saying that the token has expired.
Try presenting the UINavigationController modally from a "Login ViewController":
On app launch, the LoginVC is shown, requiring the credentials. If the login succeeds, push the UINavigationController.
When the login is invalidated (logout, cookie expires, 401 from server, ...), dismiss the UINavigationController and return to the LoginVC.
Note that on returning to the LoginVC all application state is lost, which may or may not be what you want.
Your AppDelegate should retain a reference to the LoginVC, through which you can call the 'dismiss', e.g.
[((YourAppDelegate*)[[UIApplication sharedApplication] delegate]) fallbackToLoginVC]
OK so here is what I ended up doing:
As pointed out by John Woods, don't subclass UINavigationController. Instead, I created a base UIViewController, which in its viewWillAppear checks whether the user is logged in; if not, modally present the Login screen. All View Controllers that need to check the logged-in state inherit from this base View Controller, so it becomes the "central point" for checking the logged-in state (I don't like using the AppDelegate for this kind of logic).
I like Mike Pollard's suggestion of using notifications to notify when the user's token expires (since this may happen well before viewWillAppear is called). Subscribing to this notification can then also be done in the base View Controller.
Hendrik Demmer's solution is probably the most straightforward, but I don't like having a Login screen "lurking" around at the bottom of the view controller stack - or is this just nitpicking?

How to implement an iOS login screen that only appears for unauthenticated users

I know this question is a bit open-ended but I'm trying to make it as specific as possible because I don't really know what a standard convention would be for this type of thing with iOS. I have been looking into implementing a login screen on my app, however I am having trouble figuring out the best way. I have three methods listed below, could anybody tell me if one of these is better or a more correct approach? (or if there is something that I totally missed).
The first approach - I initially have a navigation controller as my root controller with the login screen being the first view on the stack. Then when the user logs in, i just push the main UI to the stack. The user can then use the back button to return to the login screen. I know this technique works but then when re-launching the app, the user doesn't need to login again. I'm not sure should I just set up the stack the same way (login page first) and then push the main UI on top? Is that a common technique?
The next approach, I found here how to replace the root controller How to change RootViewController (in AppDelegate) from within CustomViewController? I like this idea better where I could just get rid of the login screen after login and add some type of button to bring it back on logout. Then during re-launch I can just skip adding the login screen altogether.
The third approach is perhaps overlaying the login on top of the main UI but I haven't found any code to do this. It also seems a little weird because my main UI might start firing messages that i wouldn't want to occur until after login so I'd have to account for that.
I would suggest you to have a root view controller with a blank view. This controller is set as a root view controller in the AppDelegate's applicationDidFinishLaunching: method.
Role of this root view controller would be to show the login screen through login view controller initially. Login view controller delegates to root view controller upon successful login to remove itself from root view and root view controller then set the next controller to be displayed.
This way you can manages multiple views if any before showing the main view through your root view controller.
There are different ways to display login view on top of root view.
1) Present a login view controller without animation.
2) Add login view as a subview on top of root view [Note: Before iOS 5, you don't get the rotation and view life cycle call backs and you should write your own code to pass the callbacks to the view added on top of root view. From iOS 5 onwards you have view containment concept using which you can maintain parent child relationship.]
Hope this helps.
We have a similar app. Our storyboard looks a little like a wheel.
We have a navigation controller as our root controller, which then goes to a view controller with a spinner on it. That controller handles the call to see if the user is logged in or not. It is connected to two different controllers.
If they are already logged in, it goes to the main view controller. If they haven't logged in, it goes to the login view controller. The login view controller will go back to initial view controller on success, and since they'll then be logged in, it goes to the main controller.
To fall back, we go all the way back to the initial view controller with the spinner on it.
You can hide the navigation bar on every view before the main one.
I always implement it with storyboard. Just add Storyboard ID to your login view controller, say Onboarding.
Then write something like this in application: didFinishLaunchingWithOptions:
if (![[NSUserDefaults standardUserDefaults] objectForKey:TRAIN_COMPLETE]) {
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.window.rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"Onboarding"];
}
All our ViewController are subclassed from a custom subclass of uiviewcontroller. This allow us to make powerful enhancements on behavior, constraints, ...
Our super view controller class handle authentification by summoning a modal view on viewWillAppear if user is not logged in.
Works like a charm to handle disconnection and resuming from any point in the app.

Resources