I am working on a app which have login screen. It records whether user logged in or not, in user defaults. I wanted to direct user to the login page if he has not logged in otherwise navigate to the apps main screen. How to do this programmatically using story board.
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"loggedin"]) {
//If logged in
} else {
//if logged out
}
In your appdelegate write this code. And dont forget to give identifer name to your viewcontrollers
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *viewController = // determine the initial view controller here and instantiate it with [storyboard instantiateViewControllerWithIdentifier:<storyboard id>];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
}
Why don't you always start your app with a "Loading" view. The LoadingViewController checks if the user is logged in or not and then transitions to the proper viewcontroller.
Related
I am begin to study iOS and I try to do left navigation with MMDrawerController
my AppDelegate didFinishLaunchingWithOptions code is:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *leftView = [mainStoryboard instantiateViewControllerWithIdentifier:#"LeftViewController"];
UINavigationController *leftNav = [[UINavigationController alloc]initWithRootViewController:leftView];
UIViewController *centerView = [mainStoryboard instantiateViewControllerWithIdentifier:#"CenterViewController"];
UINavigationController *centerNav = [[UINavigationController alloc]initWithRootViewController:centerView ];
self.drawerController = [[MMDrawerController alloc] initWithCenterViewController:centerNav leftDrawerViewController:leftNav];
self.drawerController.openDrawerGestureModeMask = MMOpenDrawerGestureModePanningCenterView;
self.drawerController.closeDrawerGestureModeMask = MMCloseDrawerGestureModePanningCenterView;
self.window.rootViewController = self.drawerController;
[self.window makeKeyAndVisible];
// Override point for customization after application launch.
return YES;
}
So it's work fine, but I have LoginViewController on my app, and if user has no saved token on NSUserDefaults, I must show LogionViewController.
Of course side menu must be hidden on LoginViewController.
I Tried to switch to LoginViewController inside my CenterViewController:
- (void)viewDidLoad {
[super viewDidLoad];
LoginViewController * vc = [[LoginViewController alloc] init];
AppDelegate *app = [[UIApplication sharedApplication] delegate];
[app.drawerController setCenterViewController:vc withCloseAnimation:YES completion:nil];
}
But I have black screen only.
What I do wrong?
Thanks
What you're doing is a bit weird because you are setting the new centerViewController (of type LoginViewController) within the current one (of type CenterViewController), and once that is done the latter one will be deallocated because there are no more references to it. This might somehow be causing the black screen.
One solution would be to have the LoginViewController outside the MMDrawerController, and always present it at the beginning. If there is no token, then quickly (without animation) present the MMDrawerController and the LoginViewController won't even be seen. This way also allows you to easily dismiss back to the login screen if the user logs out.
Another option is to just present your LoginViewController from the CenterViewController modally (or however you like really) using presentViewController:animated:completion:, and then just dismiss it when they log in.
I have a tab bar which contains five tabs. My application does not required user to be logged in. Only some features will be allowed if a user signups or logins.
If a user registered/logged in already, I implemented the following logic in the UserViewController which is connected to the NavigationController. However, in the following logic, user still could able to see that ViewController in one-two seconds.
-(void) viewWillAppear: (BOOL) animated
{
if(isRegistered)
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UserProfileViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"UserProfileVewController"];
[self.navigationController pushViewController:vc animated:YES];
}
}
I wonder if a user registered already, how could I skip UserViewController?
I want tabbar clicks to open directly to the UserProfileVewController rather than UserViewController which is login/signup viewcontroller.
In the project's AppDelegate, you could check if user is logged/registered or not, and display the ViewControllers dependently:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
BOOL userIsLoggedIn = AMethodCheckIfUserLoggedIn();
if (userIsLoggedIn) {
UserProfileViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"UserProfileVewController"];
self.window.rootViewController = vc;
}
else{
UserViewController *userViewController = [storyboard instantiateViewControllerWithIdentifier:#"UserViewController"];
self.window.rootViewController = userViewController;
}
//... Other logic goes here
[self.window makeKeyAndVisible];
return YES;
}
You could try having your app delegate (or whomever you want really) conform to the UITabBarControllerDelegate and implement - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController. In there you might be able to do the necessary checks/fiddling of the view controllers maybe.
I am in my first days of IOS app development, I am trying to build an authentication system for an already existent iOS App using Objective C.
The app's rootviewcontroller is a tabsview followed by navigationControllers.
What i've done so far:
1- creating the loginviewController class & designing it's UI in the storyboard
2- the same thing for the "registration" & "recover my password" classes
3- linking the root viewcontroller with the login page with a segue of type modal.
4- linking the login page with the registration & recover my password pages with segues of type push.
Now i don't know the steps that i should follow to make the login page appear to the user when he first enters the app & eventually store his state so he can access the app later without having to enter his credentials every time (unless he logs out).
Any help is greatly appreciated, thank you
I am available for any clarifications or eventually some screenshots/source code if needed.
Edit 1 : this is the content of my didFinishLaunchingWithOptions method in my appdelegate.m :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
TabsViewController *controller = (TabsViewController *)self.window.rootViewController;
controller.managedObjectContext = self.managedObjectContext;
_observer = [[MyStoreObserver alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:_observer];
//Create sub directories in doesn'n exist
NSString *documentsDirectory =[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *pathToFile = [documentsDirectory stringByAppendingString:#"export"];
BOOL isDir = YES;
BOOL isFile = [[NSFileManager defaultManager] fileExistsAtPath:pathToFile isDirectory:&isDir];
if(isFile)
{
//it is a file, process it here how ever you like, check isDir to see if its a directory
}
else
{
[self createSubDirectories];
//not a file, this is an error, handle it!
}
return YES;
}
What should I add/change ??
Set your rootViewController programmatically by checking login status.
You can save your login status as a bool in NSUserDefault after Login & Logout.
After Login
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"LoginStatus"];
After Logout
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"LoginStatus"];
Modify your appDelegate - didFinishLaunchingWithOptions: delegate method as follows
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:STORYBOARD_NAME bundle:nil];
//Check Login status
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"LoginStatus"])
{
// user not logged in
LOGIN_VIEWCONTROLLER *rootviewcontroller=[storyboard instantiateViewControllerWithIdentifier:LOGIN_VIEWCONTROLLER_IDENTIFIER];
}
else
{
// user already logged in
TABBARCONTROLLER *rootviewcontroller=[storyboard instantiateViewControllerWithIdentifier:TABBARCONTROLLER_IDENTIFIER];
}
self.window.rootViewController = rootviewcontroller;
[self.window makeKeyAndVisible];
return YES;
}
Two Options:
1) You will need database (core data) to keep track of users log. It also may help you for offline login. You can create and set property 'isLoggedIn' to find last logged in user.
2) Create and save logged-in user details in file. Refer this file for next start up. If user is logged-out , then delete that file.
Update 1:
Create login View, push tabBar on succesful login , followed by navigation controller for further flow. Refer image :
Fixed it,
I actually changed the rootviewcontroller by adding this line of code in appdelegate
LoginViewController *controller = (LoginViewController *)self.window.rootViewController;
I also changed the entry of the application in my storyboard to be loginviewcontroller.
And I also added a method called prepareforSegue in my loginviewcontroller to pass as a parameter the managed objectcontext because it caused some errors in the beginning:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"toHome"]) {
TabsViewController_iPhone *tabsViewController;
tabsViewController=[segue destinationViewController];
tabsViewController.managedObjectContext=self.managedObjectContext;
}
}
Hope to have helped someone out there. If you need more explanations on how I fixed the problem I am available. Thank's for everyone.
Edit:
After taking some time to understand how objective C works, I came to the conclusion that my answer above was not complete, so this is actually what happend:
After the user logs in the first time, I store his user & password in NSUserDefaults.
When he logs out I set the NSUserDefaults user/pass variables to Null.
So now I added a test to the AppdDelegate' didFinishLaunchingWithOptions method that says:
if the user/pass variables on NSUserDefaults are set -> go to the main menu screen of the app
else -> go to the login screen of the app.
this is the code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults stringForKey:#"username"];
NSString *password = [defaults stringForKey:#"password"];
if (username != nil && password != nil)
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
// determine the initial view controller here and instantiate it with
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"HEQMainMenuView"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
}
else
{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
// determine the initial view controller here and instantiate it with
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"HEQLoginView"];
self.window.rootViewController = viewController;
//viewController.man
[self.window makeKeyAndVisible];
}
}
Hope this helps :D
In my AppDelegate.m, I have the following code to set the initial view controller for the user at launch, depending on whether there are credentials stored in the keychain.
If the user does have credentials stored, the app will instantiate the main user interface with storyboard id, balancescreen. This works fine with the code below.
If the user does not have credentials stored, I would like to present the login view controller with storyboard id, loginscreen, modally over the top of balancescreen. When correct credentials are entered, the view controller will be dismissed (I have already handled this), with the user shown the main interface. This is what I need help with, finding a solution to do this without glitching the application.
This is the code I currently have:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// grabs password for the only account
// (there shall always only be one set of credentials stored so this will work)
NSString *password = [SSKeychain passwordForService:#"MyOpal" account:[[SSKeychain accountsForService:#"MyOpal"][0] valueForKey:#"acct"]];
// if password has a length (aka user has previously used the application with credentials in keychain), direct to the app
// if password has no length (aka does not exist because user has not used the application before), direct to login screen
if (password.length > 0) {
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"balancescreen"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
} else {
// do something here to present login view controller modally over the top of the main interface (with storyboard id, 'balance screen')
// therefore, when the user logs in, the login view controller will dismiss, with the user greeted at the main interface
}
return YES;
}
Edit: This is my storyboard set up:
Don't change the rootViewController in your application. Make the rootViewController receive the request to navigate to login or to application.
Changing the rootViewController of the window is bad practice as you need to do animations manually. A storyboard flow would look like this:
Try this:
if (password.length > 0) {
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"balancescreen"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
} else {
// go on as before
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"balancescreen"];
// instantiate the LoginViewController
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
// present the LoginViewController modoally with viewController as presenter
[viewController presentViewController:loginViewController animated:NO completion:nil];
}
Obviously I am assuming that your UIViewController that handles the login is called LoginViewController. If that's not the case, just go on and adjust its name in your code :)
Anyway, for this kind of situation I would rather recommend you to not present the login modally. A better approach is to actually change the rootViewController property of your application\s main UIWindow.
That could look like this in your case:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
if (password.length > 0) {
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"balancescreen"];
self.window.rootViewController = viewController;
}
else {
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
self.window.rootViewController = loginViewController;
}
[self.window makeKeyAndVisible];
I have two view controllers, a default ViewController and the one I added later for login: LoginViewController. I set LoginViewController as initial view. But when I run the app, after viewDidLoad in LoginViewController it fires -viewDidLoad in ViewController also.
I have a modal segue, after login is successful to perform segue and show me the ViewController, that works. But in execution of app ViewController is also fired. Does anyone have an idea why this happens? AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
UIViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"LoginView"];
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}