I've been struggling with this a long time now, so I finally gave up on trying to find the answer and decided to ask it right away.
On my app I have a user log in page. The app has a TabBarViewController that has some NavigationControllers in it's items.
My last effort was to put the login screen embedded on a NavigationBarController and make it the Initial View Controller, as in the picture below.
When the app is launched, if the user is logged in the LogInViewController 'segues' to the TabBarController and everything is fine. When the user logs out in the ProfileViewController, there's a segue in this ViewController 'segueing' to the initial view controller.
In the other hand, if no user is logged in, the LogInViewController presents a view so that the user can insert username and password. If credentials are correct the LogInViewController 'segues' to the TabBarController. The problem is that at this point, even if the app is still working good, i get the following warning:
Warning: Attempt to present TabBarViewController: 0xa19a670 on UINavigationController: 0xa526370 while a presentation is in progress!
So I assume this is not the best way to handle all this LogIn/LogOut process.
My question is, where should I put the LogInScreen in the hierarchy?
If by any chance my layout/hierarchy is correct, how to make the warning go away?
You should make your Home screen as your rootViewController and in once your application starts or become active, you can check if user is logged in or not, if not then present the LoginScreen Modally, it will avoid the mess with other NavigationController or TabBarController
Alternate could be to put all the ViewControllers in a MutbaleArray and set the current Index of TabBarController according to the view you want to show? if you don't want to show the LoginScreen after user Logged in, just remove it from your MutableArray, check my answer here, it might help your cause
Related
I am hoping for a quick tip or strategy on this problem and see how you have or would solve this.
At launch, I am checking for the user "status." This basically means:
1. Check if they have a session in progress aka.. they are logged in
2. Check if they have entered in a Credit Card yet
3. Check if they have clicked on a confirmation email
Based on whether these statuses are true or not, I want to segue at launch to the appropriate viewcontroller (ex: if no CC detected, segue to a credit card entry page ... etc).
Currently, my iOS8 setup is as follows:
1. Checking user "status" in didFinishLaunchingWithOptions: in the appdelegate
2. I have a launch screen xib that (as far as I know) cannot have a viewcontroller attached (therefore I cannot segue at that point which would be most ideal).
Does anyone know a way to tackle this problem?
Thanks!
I presume you are using a storyboard. That's part of the problem here, but it is not insuperable. By the time your code in didFinishLaunching... runs, you already have a window and that window has a root view controller. Thus you can get a reference to that root view controller and do any pushing or presenting of a different view controller on top of it. And since you are doing this before the interface is shown, your interface will appear with the desired view controller showing.
But be careful not to do anything time-consuming. I don't know what all this "checking" involves but if it takes any time, the watchdog will kill your app dead for taking too long to launch. It is better to launch into your root view controller and then do your checking - even if this means the user will see the root view controller for a while. Just design a root view controller that is okay to show.
I'm trying to create a view which have a side-window menu using SWRevealViewController. In the menu, I need to load UserID from LoginViewController and load the user name and photo in it. I used NSUserDefault for this. The problem is, whenever I logged out and login back using different account, the new account name and photo will stack up with the previous instead of rewrite it.
After looking here and there, I found that the problem may because the loginviewcontroller loaded after navigationcontroller and the navigationcontroller loaded after swrevealviewcontroller. I tried to move the rootview to uiloinviewcontroller but it's not working because of the navigationcontroller.
I also tried to clear the NSUserDefault when I hit logout button but nothing seems working.
Can you please help me, how I can fixed this problem?
I'm writing an iOS application that includes a UITabBarController, where one of the tabs is the user's profile. However, if the user is not signed in, I would like the application to display a different ViewController (Sign in/Sign up) instead.
I currently have the profile tab routing to a navigaion controller which has its RootViewController as ProfileViewController. In ProfileViewController's viewDidLoad, I have a check to see if the user is signed in. If the user is not, It performs a segue to SignInSignUpViewController which eventually loops back to ProfileViewController.
This approach is over-complicated and broken in a couple ways. For example, the navigation controller allows for the user to back into the signup/signin view controller after they've already signed in.
I feel like this is a pretty common idiom in iOS, but I can't find a good solution online. Anyone have any ideas?
Thanks in advance!
You might want to take a look at the UINavigationController method – setViewControllers:animated:. After you've logged in call this and pass your profile ProfileViewController. It will then be at the top of the stack, so the user won't be able to navigate back to the login view controller.
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?
I am looking for feedback on a best practice approach when you want to present a LoginViewController as a "ModalViewController" in an app with TabBarController.
The case is this:
- Application supports user sessions with login/logout functionality
- When the app is launched it tries to login automaticly and either display TabBarController directly or the LoginViewController (displayed as a ModalViewController to enable a dismiss animation on login)
- The application has a TabBarController with a number of tabs.
- Each time a ViewController is presented the user's state is checked
- If the user isn't logged in a ModalViewController with login functionality should be presented
- If the user manually logout the same ModalViewController should be presented
I have tried to come up with several different designs to handle this and no one feels completely "correct". I have worked on one project where this was handled using a subclassed UIWindow which replaced the apps default UIWindow. The subclass then listened for different Notifications such as "UserLoggedInSuccessfully", "UserLoggedOut" etc, to handle presentation of the ModalViewController.
Are there any other solutions to this? I would appreciate any input and experiences of this kind of solution.
There are different solutions for this problem , you could try these alternatives but first one is the recommended approach I would say,
You can make your HomeViewController which will be first tab of TabBarController as default to open every time, and make the LoginViewController separately, in your AppDelegate you could check the login session in didFinishLaunchingWithOptions and if the session is not valid then show the LoginViewController as ModalViewController otherwise show the TabBarController with all the tabs included.
Alternative could be to have all the Controllers in The Tab but when you present LoginViewController , after user has signed in, add all the controllers in a MutbaleArray and delete the current object which is LoginViewController. Once user is signed in , save the info in the keychain and this way user will not have to login again and again, this way you can avoid showing the LoginViewController every time, once user tries to log out , then add the LoginViewController in an Array and then add all the TabBarController objects after LoginViewController.
You may to do the following ,
when user open the app you have to show hime the loginviewcontroller as the rootviewcontroller then when login successfully you have to make the tabbarviewcontroller as the rootViewcontroller .
then each time when the user run the app you have to check if he has a valid session you will make a tabar as a root
if the the session expire when you on the tabbar , you have to change the root view controller from your app delegate to sign in