App is crashing while using SWRevealViewController - ios

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

Related

Skip the Login View Controller when user is already login in IOS

I have a home screen with a button on it , when we click a button it shows a login screen, the user get login through phone number , if user enter number which is not register before it shows button on screen to go to the register form screen, Now i'm trying that if user is already login then whenever it opens the app the login screen should not be seen , it should directly go to the next screen which comes after login, if user is not login before then it should show login screen. My code is,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
if([[NSUserDefaults standardUserDefaults] valueForKey:#"login"])
{
// So, here user already login then set your root view controller, let's say `SecondViewController``
HomeViewController *secondViewController = [storyBoard instantiateViewControllerWithIdentifier:#"HomeViewController"];
// then set your root view controller
self.window.rootViewController = secondViewController;
} else
{
// It means you need to your root view controller is your login view controller, so let's create it
RegisterViewController *loginViewController= [storyBoard instantiateViewControllerWithIdentifier:#"RegisterD"];
self.window.rootViewController = loginViewController;
}
// Override point for customization after application launch.
return YES;
}
use boolforkey insted value for key as
[[NSUserDefaults standardUserDefaults] boolForKey:#"login"]
You can set current user login state using NSUserDefault.
On next app launch, on home view controller, When you click on that button, before loading login screen, check user login status. If it is true, then load next screen directly, and if not redirect to the login screen.
func loginButtonOnHomeScreen(sender:UIButton){
let loginState = UserDefaults.standard.bool(forKey: "Login")
var VC:UIViewController
if loginState == true{
VC = (self.storyboard?.instantiateViewController(withIdentifier: "NextScreen"))!
}else{
VC = (self.storyboard?.instantiateViewController(withIdentifier: "LoginScreen"))!
}
self.navigationController?.pushViewController(VC, animated: true)
}
Hope this will help
edit
n Objective C
BOOL loginState = [[NSUserDefaults standardUserDefaults] boolForKey:#"Login"];
UIViewController *VC;
if (loginState == true){
VC = [self.storyboard instantiateViewControllerWithIdentifier:#"NextScreen"];
}else{
VC = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginScreen"];
}
[self.navigationController pushViewController:VC animated:true];
When user login/register successfully set
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"login"];
When user logout at that time remove from NSUserDefaults or set false
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"login"];
OR
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"login"];
you can check user is already login or not in appDelegate file or any other your suitable screen
if([[NSUserDefaults standardUserDefaults] boolForKey:#"login"])
{
//YES Already Login
NextController *nextVC = [self.storyboard instantiateViewControllerWithIdentifier:#"NextController"];
}
else
{
//NOT Login
LoginController *loginVC = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginController"];
}
You have 2 ViewController (LoginVC and HomeVC),
First write bellow code in "LoginVC"
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"loggedIn"]){
nslog(#"Success"};
}
else{
nslog(#"Login Agin")
}
Second code write in HomeVC(This After login)
-(void)viewWillAppear:(BOOL)animated{
[[NSUserDefaults standardUserDefaults]setBool:YES forKey:#"loggedIn"];
}

IOS & objective C development - how to make the login page appear to the user?

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

Selecting StoryBoard in AppDelegate based on logged in or not

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

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.

Facebook iOS SDK, Logout (CloseAndClearTokenInformation) not working?

I've set up the Facebook iOS SDK with my app, and everything works fine. I can login using Facebook, but for some reason when I try and click my "Logout" button (top right, see image below), it doesn't do anything. I'm using a Storyboard to create my app (the login xib opens on top of my existing storyboard), and everything in my AppDelegate seems correct. What am I missing? See snippets of code below.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.mainViewController = [[SSViewController alloc]
initWithNibName:#"SSViewController" bundle:nil];
self.navController = [[UINavigationController alloc]
initWithRootViewController:self.mainViewController];
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
// Yes, so just open the session (this won't display any UX).
[self openSession];
} else {
// No, display the login page.
[self showLoginView];
}
return YES;
}
- (void)showLoginView
{
UIViewController *topViewController = [self.navController topViewController];
UIViewController *modalViewController = [topViewController modalViewController];
// If the login screen is not already displayed, display it. If the login screen is
// displayed, then getting back here means the login in progress did not successfully
// complete. In that case, notify the login view so it can update its UI appropriately.
if (![modalViewController isKindOfClass:[SSLoginViewController class]]) {
SSLoginViewController* loginViewController = [[SSLoginViewController alloc]
initWithNibName:#"SSLoginViewController"
bundle:nil];
[topViewController presentViewController:loginViewController animated:NO completion:nil];
} else {
SSLoginViewController* loginViewController =
(SSLoginViewController*)modalViewController;
[loginViewController loginFailed];
}
}
SSViewController.m
-(void)logoutButtonWasPressed:(id)sender {
[FBSession.activeSession closeAndClearTokenInformation];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithTitle:#"Logout"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(logoutButtonWasPressed:)];

Resources