Starting app with login page when tab bar controller is present - ios

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.

Related

Modally presented view causes previous view to disappear when navigating away/to with tab bar view controller

I'm working on UITabBarController based app. The app has a concept of "user authentication/restriction" where particular tabs may become restricted/unrestricted at any point in time (via an admin).
When restricted, a "authentication" view is presented over the tab's current view. This is done simply via storyboard segue ways and is presented with "Kind" of "Present Modally" and "Presentation" of "Over current content"
Everything works just fine so long as the user doesn't navigate to a different tab while the "authentication" view is presented and back again after authorisation has been granted, in this case, the presenting view is blank
In its present form, I'm using the authentication view's viewDidLoad to check if the user is restricted or not, if they aren't, I'm triggering a return segue to the parent view, this means if the tab was restricted, but becomes unrestricted, the authentication view can be dismissed automatically
So, the sequence of events
User navigates to a "possibly restricted" tab/view
Restriction state requires authentication, the authentication view is presented
The user navigates to a different tab and back again and enters the authentication (or restrictions are lifted) and the authentication view is dismissed
Parent view is blank
I'm at a lose at how to resolve this.
I've tried (in the unwind segue method of the parent view)
view.setNeedsLayout() and view.setNeedsDisplay() in the parent view in response to the segue event from the authentication view
I've tried navigationController?.popToViewController(self, animated: false)
I've tried popping and pushing the view again
I've tried table.reloadData() (yes, the parent view is just a UITableViewController)
I've tried removing and re-adding the view, but probably did it wrong
I'm at a wits end in trying to get the view controller to perform a full refresh/reload
Update
I've been able to devise "a" solution, basically when viewWillDisappear is called on the authentication view, I perform a special "unauthorised dismissal" segue, the intention of which is to tell the parent view that the authentication view has been dismissed, but no authentication took place, letting it know that it should not try and update itself, but also not try and re-authenticate.
This allows the parent's viewDidAppear method to handle the authentication process again once it's made visible.
It works for me, but I'm open for more ideas

UINavigationController limited utilization in app design

I am using the NavigationController (Embedded via Editor drop down menu in xCode) to control navigation on sign-up and sign-in views, all from landing view when app first launched.
After user sign-up or login, I would like to initiate a view controller with no relation to the NavigationController. Nonetheless, from Sign-up and Login views, I have a segue that links (upon successful authorization) to the main view of logged in users. How can I remove the navigation controller from a certain part of the application because it is no longer needed? Otherwise, each time I add a new view controller, it shows the navigation bar in it which is not ideal for design.
Thanks and image attached shows what I need illustrated.
As far as I am concerned you can remove only view controller from navigation stack. If you do not want navigation bar to be visible, then just hide it in viewWillAppear of view controller that you want to be without navigationBar.
[self.navigationController setNavigationBarHidden:<#(BOOL)#> animated:<#(BOOL)#>]

How to skip a login view controller?

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.

Pushing view controller from app delegate

So recently I had to reorganize my tab bar and remove one the tabs for a view controller that I still need to access at the end of the app. I am using NSNotifications which triggers a method in the app delegate which basically switches the tab [self.myTabBar setSelectedIndex:REC_TAB];
Worked like a charm. Now that I can no longer select the tab, I'm finding I'm having trouble pushing/popping/presenting a view controller from the app delegate.
I'm new to this so any help would be appreciated.
There's no reason that you have to do it from the app delegate -- you can if you want to, but there's no need. From any view controller, you can access the window's root view controller with self.view.window.rootViewController, and change it to whatever you want. Another way is to just present a modal view controller with presentViewController:animated: from any view controller.

About tab bar using storyboard

I want to create an app using storyboard that has login window and tab bar controller.
So the flow will be upon tapping the login button, the app will be redirected to tab bar controller with its views.
I have done this:
But referring to Apple Documentation: UITabBarController
Because the UITabBarController class inherits from the
UIViewController class, tab bar controllers have their own view that
is accessible through the view property. When deploying a tab bar
interface, you must install this view as the root of your window.
Unlike other view controllers, a tab bar interface should never be
installed as a child of another view controller.
So that means I am not allowed to do so?
In addition:
The 3 views that are referred by my tab bar, then each of them has their own child view again, but the tab bar in the child view is gone. What could be happen? Am I missing something?
What I have done in all my apps that are structured similarly is to have the first view controller check for valid authentication and if that fails, present a login VC. That login VC has a delegate defined that will pass back the user credential after a successful login and then dismisses the modal login VC does whatever.
Here is a sample layout:
The delegate protocol looks like this:
#protocol LoginViewControllerDelegate
-(void)finishedLoadingUserInfo:(UserInfo *)curUser;
#end
Where UserInfo is the model I use for the user information (in my case, NetworkID, FullName, etc).
When the user has successfully authenticated, I fire off that delegate method which is handled in the class that presented it. If you need more detail, I can help - but the process is simple.
You can launch your login screen first from the appDelegate and then setup and launch the tabBarViewController after the login is successful.
An alternative design is to do the following steps:
1. set up your tabBarViewController,
2. disable the tabs,
3. launch your login view controller modally,
4. enable tabViewController tabs
Either of these two approaches should work.

Resources