Selecting StoryBoard in AppDelegate based on logged in or not - ios

I am trying to Display Selected ViewController based on user has Logged in inside the app or not.if user has logged in then it should display HomeViewController, if not then it should display InitialViewController.My Initial StoryBoard is MainStoryBoard and LoginVC are in InitialStoryBoard. Below is my sample code and struggling lot to fix this issue.can anybody help to fix this issue .
/- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions*
/
BOOL isLoggedIn = [[NSUserDefaults standardUserDefaults]boolForKey:#"isLoggedIn"];
NSLog(isLoggedIn ? #"Yes" : #"No");
NSLog([[NSUserDefaults standardUserDefaults]boolForKey:#"isLoggedIn"] ? #"Yes" : #"No");
if (!isLoggedIn) {
NSString *device2;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
device2 = #"InitialStoryboard_iPad";
}
else
{
device2 = #"InitialStoryboard_iPhone";
}
NSLog(#"device :%#",device2);
UIStoryboard *storyboard2 = [UIStoryboard storyboardWithName:device2 bundle:nil];
InitialVC *initialController = [storyboard2 instantiateInitialViewController];
// [(UINavigationController *)self.window.rootViewController presentViewController:initialController animated:YES completion:nil];
// [(UINavigationController *)self.window.rootViewController pushViewController:initialController animated:NO];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = initialController;
[self.window makeKeyAndVisible];
}
If Login is Successful then i am not able to dismissCurrentVC as Initial is RootVC.If login is Successful then it should make DismissVC if MainStoryBoard is Initial Storyboard.or login Successful should make HomeVC PresentVCModally if InitialStoryBoard is InitialStoryboard.Hope you can understand my Issue.
Thanks in Advance

Instead of using different storyboards, I suggest you use only one storyboard (for each device) which contains the RootVC and LoginVC. (RootVC is default initial VC)
if([[NSUserDefaults standardUserDefaults] stringForKey:#"userName"].length){
NSLog(#"User Logged In, Show Root VC");
//RootVC is Default.
}else{
NSLog(#"User Not Logged In, Show Login NVC");
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"LoginNVC"];
}
After user logged in, you can then switch back to rootVC:
- (void)loginAndShowRootVC{
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"RootVCID"];
}

Related

App is crashing while using SWRevealViewController

I am using SWRevealViewController for Slide Out Menu for an application in which slide out menu starts only from the Home Screen after Sign Up button is pressed in SignUp page(i.e. running the application for the first time).
When the app is running for the second time it is suppose to go directly to the Home Screen,but the app is crashing, and I am getting crash log in ViewController.
_barBtnMenu.target = self.revealViewController;
_barBtnMenu.action = #selector(revealToggle:);
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
NSInvalidArgumentException', reason:'-[__NSArrayM
insertObject:atIndex:]: object cannot be nil.
For app's first time run I am using Present Modally Segue from Sign Up button.
In SWRevealViewController
- (SWRevealViewController*)revealViewController
{
UIViewController *parent = self;
Class revealClass = [SWRevealViewController class];
while ( nil != (parent = [parent parentViewController]) && ![parent isKindOfClass:revealClass] ) {}
return (id)parent;
}
While running it for the first time
parent is returning a value but for the second run it is returning nil
If anyone could help me in solving the issue.
Thanks in advance.
EDIT
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"email"];
if (savedValue != nil) {
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
ViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"viewController"];
self.window.rootViewController =viewController;
[self.window makeKeyAndVisible];
} else {
NSLog(#"Sign Up screen opened");
}
return YES;
}
You are trying to implement Autologin feature in your app
for the second launch you have to maintain a flag in Appdelegate that user is already logged in or not , if user is already logged in you have to move to the parent controller of SWRevealview from didfinishlaunchingwithoptions function in app delegate.
for that save username and password to userdefaults at login & signup
check for values in didfinishlaunchingwithoptions
if value exist move to parent of SWrevealview
Thanks for the replies,
I solved it by making SignUp page as Root view
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"email"];
if (savedValue == nil) {
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
SignUpViewController *signUpViewController = [storyboard instantiateViewControllerWithIdentifier:#"signUpViewController"];
self.window.rootViewController = signUpViewController;
[self.window makeKeyAndVisible];
} else {
NSLog(#"Sign Up screen closed,Hom page opened");
}
return YES;
}

issue while changing Navigation Root View Controller

I am making an app. In which First User have to sign In then He allowed to use the app.
After successful login I want the user to directly switch to my HomeViewController.
Here is my code tho change navigation root view but it is not working
TermsConditionsController *firstViewController = [[TermsConditionsController alloc]init];
FirstPage *secondViewController = [[FirstPage alloc]init];
firstViewController.navigationController.viewControllers = [NSArray arrayWithObject: secondViewController];
FirstPage *nextScr = (FirstPage *) [self.storyboard instantiateViewControllerWithIdentifier:#"FirstPage"];
[self.navigationController pushViewController:nextScr animated:YES];
Connect your LoginViewController with HomeViewController by using segue.
give the identifier for the segue for ex name:successLogin.
and use this method:
[self performSegueIdentifier:#"successLogin" sender:nil];
Try this code
Note: Change controller name as per your controllers
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UINavigationController *navController;
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"loginUserDetails"]) {
// Already logged in
ProfileViewController *profileVC = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ProfileVC"];
navController = [[UINavigationController alloc]initWithRootViewController:profileVC];
}else{
// Not Login Yet
LoginViewController *loginVC = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"LoginVC"];
navController = [[UINavigationController alloc]initWithRootViewController:loginVC];
}
self.window.rootViewController = navController;
}
// Write this code when user login successfully
if (/*Login Successfully*/) {
// Then add loginUserDetails in userdefaults.
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"loginUserDetails"];// Instead of nil pass here your object
[[NSUserDefaults standardUserDefaults] synchronize];
}

Present modal view controller over view controller at launch

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

How to programmatically set which screen load first by story board

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.

iOS How to go to Previous to Previous View

I have a situation where I want to go from Previous to Previous view.
A MainView calls modal CWViewC calls modal CRViewC & that calls modal CRDViewC - on a action event in CRDViewC I need to return to CWViewC & update a component of it.
I want to use navigationController in my app, but am not able to set it, hence right now am not using it at all. I also am scared to play with Segue's also thinking that it might affect the compatibility of the app :(. I searched on net for similar situation but can't find a solution.
I could think of sending any sort of notification to CWViewc from CRDViewC. But again how to implement it in both respective classes & how to get rid of (I mean close) CRViewC then.
So please suggest and guide me for the same to solve the problem.
Any help is highly appreciated. Thanks.
EDIT :
My req was I have to call LoginVC prior & my main scrn is MAinTabVC. So I have made my app as TabbedTemplate & I call my LoginVC from AppDelgate & on when logged in successfully, from AppDelegate my MainTabVC comes up. This is how I call my login :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Get the StartupData properties from device
MC_Utility *utility = [[MC_Utility alloc] init];
self.theAppDataObject.startupData = [utility retrieveLocalData];
NSLog(#"READ Loigin On Launch - %#", self.theAppDataObject.startupData.loginOnLaunch);
utility = nil;
// Show Login view if not logged On
if (!self.isLoggedIn) {
[self showLoginScreen:NO];
}
return YES;
}
-(void) showLoginScreen:(BOOL)animated {
// Get login screen from storyboard and present it
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"loginViewController"];
// Show Login
if (theAppDataObject.startupData.loginOnLaunch.boolValue == true) {
NSString *email = #"dylan#antila.co";
NSString *pswd = #"t4Wzpg4OQ5q8ZNVDPPo7wg==";
[loginViewController startLoginProcess:email :pswd];
} else {
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:loginViewController animated:animated completion:nil];
}
}
Other all views that I normally show using such code :
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
MC_ChatWindowViewController *chatWindVC = [storyboard instantiateViewControllerWithIdentifier:#"chatWindowVC"];
[chatWindVC setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentViewController:chatWindVC animated:YES completion:nil];
In my AppDelegate, I had tried to call mainTabVC, but wasn't successful. So stuck to original code. Tried several ways thru few tutorials also, but couldn't do it. I am a newbie in iOS development & am not finding comfortable yet to work with navControllers.
I have embedded NavController in LoginVC thru storyboard.
CODE Added in MAinTAB .m
#implementation MC_MainTabBarController
bool isLogged = false;
-(void) showLoginScreen:(BOOL)animated {
NSLog(#"Calling Login from MainTab");
// Get login screen from storyboard and present it
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"loginViewController"];
[loginViewController setModalPresentationStyle:UIModalPresentationFullScreen ];
[self presentViewController:loginViewController animated:YES completion:nil];
/* AUTO LOGIN
// Show Login
if (theAppDataObject.startupData.loginOnLaunch.boolValue == true) {
NSString *email = #"dylan#antila.co";
NSString *pswd = #"t4Wzpg4OQ5q8ZNVDPPo7wg==";
[loginViewController startLoginProcess:email :pswd];
} else {
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:loginViewController animated:animated completion:nil];
} */
}
-(void)viewWillAppear:(BOOL)animated {
if (isLogged == false) {
[self showLoginScreen:YES];
}
}
As you mentioned segues, can I safely assume you're using storyboards? If so, get your first view controller (the one with MainView) in the storyboard file, go to the Product menu in the menu bar and select Embed In>Navigation Controller,as shown in this screenshot:
Then, change those segues between your view controllers to be Push rather than modal, so the one from mainView to the CWViewC will be Push, then the one from CWViewC to CRViewC will be Push and so on.
The views won't be modal, but this is a much more natural way of progressing through a stack of views.

Resources