How to skip a login view controller? - ios

I develop an iOS app and my initial view controller shows a login form. Then when the user successfully authenticates the actual application is presented as a modal view controller.
When the user logs out the application it is dismissed and the login view controller is visible again.
My problem is:
When the application is started again and the user already is logged in I don't want to show the login view controller. I can't present the view controller before the login view controller is fully shown:
Warning: Attempt to present <UITabBarController: 0x10a271b40> on <LoginViewController: 0x10a2594f0> whose view is not in the window hierarchy!
I can present it with a delay but this is not what I want.
I could check if the user is logged in before I show a view (in the app delegate) and then show the login or the application. The problem with this is:
When the user logs out I have no login view controller beneath my application to which I can pop.
I can't find a good solution except defining the actual application as the root and present the login over it. But this brings a lot new problems because the main application needs data structures I can only initialize after login.

You don't want to be running with a modal always shown, it will be easy to inadvertently dismiss your 'entire app'.
Instead, do as you suggest in the app delegate where you decide which view controller is required and change the root view controller of the window. Again, when the user logs in / out, change the windows root view controller.

Most Application flow will be like that.
1) Set your tabbar controller as rootviewcontroller. When application launch, check with login status and show your tabbar(rootviewcontroller) if already logged in. Otherwise present modal view as loginview controller from tabbar(tabbar is rootviewcontroller).
2) When logout success, again show loginView as modal view(tabbar is rootviewcontroller).
Note: You can also shift rootviewcontroller as tabbar and loginview. But I recommented above flow.

Related

What happens to a View Controller after it has modally presented another View Controller

Consider the following structure of an app:
Login Screen --> Splash Screen --> Main use (--> Logout page --> New Instance of Login Screen)
When the user logs in from the Splash Screen, I present the Splash Screen Modally from the Login Screen. When the Splash Screen have completed it's tasks, I present the Main Use View (Which is a UITabController) modally from the Splash Screen. If at some point the user decides to logout of the app, I remove the credentials and present a new Instance of the Login Screen modally from the Main Use View.
I recently started doubting that this works as I expect it to. Say that the user have navigated all the way to Main Use, are the presenting View Controller (Splash Screen) and it's presenting View Controller (Login Screen) still active and present in the Hierarchy? After Modally presenting another View Controller, I expect the first View Controller to be completely unloaded and forgotten by the System, as if it was set to null. Can someone confirm this? And in case this doesn't work as I expect it to, what should I do instead of modally presenting View Controllers?
Your doubts are warranted. When you present a modal view controller, it goes on top of the existing view controller and covers it, but the existing view controller does not go away. You never want to present a new copy of a view controller without dismissing the previous one.
(Using dismiss(animated:completion:).)

View Controller Setup

I am trying to figure out the best way to get my view controllers setup according to the design I am given. My app starts off with a full screen login screen. The user logs in and then the next view is a 3 tab screen. Where clicking on any control in any of the 3 tabbed view, need to take you to a full screen view controller.
Now the problem I am facing is that
1) The guidelines say not to put a TabBarController in a NavigationController, which in this case I have to do.
2) Also If I set the ViewControllers of each TabBarView to be a navigation controller, then I don't get the full screen space as the bottom always shows the tab bar, which I don't need to see.
Thoughts and pointers gladly appreciated.
The way that I would set it up would be to have a global container view controller that manages all of the internal view controllers. Example:
=============================
= Container View Controller =
=============================
| |
------------ -----------
- Login VC - - Main VC -
------------ -----------
Then, the workflow for app launch would be as follows:
Application launches and the container/splash view controller is the root view controller.
Container view controller determines login status (shows a loading indicator perhaps, etc).
Transition to the correct view controller.
If the user is not logged in, you could transition to the login view controller. From there, you could subscribe to either a delegate callback or a notification which would be dispatched once the user logs in. Once that message is received, you could re-check the login status and show the view controller accordingly.
If the user is logged in, at either the start or after receiving the login callback, then just show the main view controller.
Logout would work the same way as login. Just push a notification to the container view controller and have it manage the view controllers accordingly.
Personally, I would use a tabBarController as your initial view controller. If the user is not logged in, immediately present (modally) your login view controller. Dismiss the login controller once the user has logged in, and return to the tabBarController. Wrap the view controllers for each tab in a navigation controllers, but set hidesBottomBarWhenPushed in order to hide the tabBar.

Starting app with login page when tab bar controller is present

I have conditional code in my app delegate's didFinishLaunchingWithOptions: method that uses HTTP requests/responses to determine if the user is logged in already. I'm running into serious hierarchy problems, and my question is this: should I be starting my app with the login page (and make the app delegate conditionally load my tab bar when the user is logged in already), or start with my tab bar (and make the app delegate conditionally load my login page)?
This is my storyboard currently
I would make the tab bar controller the root view controller of the window, and present the login controller from the viewDidAppear method (without animation) of the controller in the first tab. Also, you should not go backwards in a storyboard with a segue, unless you use an unwind segue. Segues (other than unwinds) alway instantiate new controllers, so you're not actually going back to a previous controller, you're instantiating a new one. This will cause more and more controllers to be added to your hierarchy as the user navigates back and forth.

What's the proper way to manage login state + login view (using storyboards)?

It's the first app that I'm creating that will use FB, Twtr and custom login.
I'll be using a dedicated login view/viewcontroller for this purpose.
My idea was to check the login state in the app delegate and go from there.
In case app delegate determines the user is not logged in
Set the login view as the root view controller
Login will display the rest of the app modally
If you log out, the modal view of the app is dismissed and you get back at the login screen
So in this case it looks perfect for me, but I can't figure the other case out:
In case app delegate determines the user is logged in
If you set the tabbar controller as the rootViewController there is no login view to dismiss to in case the user logs out..
I don't want the user to view the login screen if he is already logged in
A solution would be to invisibly set login vc as the root vc but immediately display the tab bar controller modally without the user noticing. I guess that's not possible?
You should always start with the Login screen at the root. The login views should be invisible and a UIActivityIndicator (or similar) should be shown while you determine if the user is logged in.
If the user is logged-in, simply push the next view controller and continue normally. If he isn't un-hide the login views.

Using UISplitViewController in iOS

I want to add a split view controller when the login button is clicked on the login screen (when user is successfully logged in). I want to show another view controller which is a split view controller with a master controller and detail controller.
SplitViewControllers are intended to be used as the root view controller. So you will need to create your login viewController and attach it to the window. Then when the user logs in you will have to remove the login viewController and then create a new SplitViewController and attach that to the window instead.
If you search you should find threads that help e.g.
How to implement SplitViewController on second level.?
I know there are also threads showing how to do this for tabBarControllers and the process is the same.

Resources