Best Practices For Storyboard Login Screen, Handling Clearing Of Data Upon Logout


Answer :

Your storyboard should look like this

In your appDelegate.m inside your didFinishLaunchingWithOptions

//authenticatedUser: check from NSUserDefaults User credential if its present then set your navigation flow accordingly  if (authenticatedUser)  {     self.window.rootViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateInitialViewController];         } else {     UIViewController* rootController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"LoginViewController"];     UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:rootController];      self.window.rootViewController = navigation; } 

In SignUpViewController.m file

- (IBAction)actionSignup:(id)sender {     AppDelegate *appDelegateTemp = [[UIApplication sharedApplication]delegate];      appDelegateTemp.window.rootViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateInitialViewController]; } 

In file MyTabThreeViewController.m

- (IBAction)actionLogout:(id)sender {      // Delete User credential from NSUserDefaults and other data related to user      AppDelegate *appDelegateTemp = [[UIApplication sharedApplication]delegate];      UIViewController* rootController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"LoginViewController"];      UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:rootController];     appDelegateTemp.window.rootViewController = navigation;  } 

Swift 4 Version

didFinishLaunchingWithOptions in app delegate assuming your initial view controller is the signed in TabbarController.

if Auth.auth().currentUser == nil {         let rootController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "WelcomeNavigation")         self.window?.rootViewController = rootController     }      return true 

In Sign up view controller:

@IBAction func actionSignup(_ sender: Any) { let appDelegateTemp = UIApplication.shared.delegate as? AppDelegate appDelegateTemp?.window?.rootViewController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateInitialViewController() } 

MyTabThreeViewController

 //Remove user credentials guard let appDel = UIApplication.shared.delegate as? AppDelegate else { return }         let rootController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "WelcomeNavigation")         appDel.window?.rootViewController = rootController 

Here is what I ended up doing to accomplish everything. The only thing you need to consider in addition to this is (a) the login process and (b) where you are storing your app data (in this case, I used a singleton).

Storyboard showing login view controller and main tab controller

As you can see, the root view controller is my Main Tab Controller. I did this because after the user has logged in, I want the app to launch directly to the first tab. (This avoids any "flicker" where the login view shows temporarily.)

AppDelegate.m

In this file, I check whether the user is already logged in. If not, I push the login view controller. I also handle the logout process, where I clear data and show the login view.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {      // Show login view if not logged in already     if(![AppData isLoggedIn]) {         [self showLoginScreen:NO];     }      return YES; }  -(void) showLoginScreen:(BOOL)animated {      // Get login screen from storyboard and present it     UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];     LoginViewController *viewController = (LoginViewController *)[storyboard instantiateViewControllerWithIdentifier:@"loginScreen"];     [self.window makeKeyAndVisible];     [self.window.rootViewController presentViewController:viewController                                              animated:animated                                            completion:nil]; }  -(void) logout {     // Remove data from singleton (where all my app data is stored)     [AppData clearData];     // Reset view controller (this will quickly clear all the views)    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];    MainTabControllerViewController *viewController = (MainTabControllerViewController *)[storyboard instantiateViewControllerWithIdentifier:@"mainView"];    [self.window setRootViewController:viewController];     // Show login screen    [self showLoginScreen:NO];  } 

LoginViewController.m

Here, if the login is successful, I simply dismiss the view and send a notification.

-(void) loginWasSuccessful {       // Send notification      [[NSNotificationCenter defaultCenter] postNotificationName:@"loginSuccessful" object:self];       // Dismiss login screen      [self dismissViewControllerAnimated:YES completion:nil];  } 

EDIT: Add logout action.

enter image description here

1. First of all prepare the app delegate file

AppDelegate.h

#import <UIKit/UIKit.h>  @interface AppDelegate : UIResponder <UIApplicationDelegate>  @property (strong, nonatomic) UIWindow *window; @property (nonatomic) BOOL authenticated;  @end 

AppDelegate.m

#import "AppDelegate.h" #import "User.h"  @implementation AppDelegate  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {     User *userObj = [[User alloc] init];     self.authenticated = [userObj userAuthenticated];      return YES; } 

2. Create a class named User.

User.h

#import <Foundation/Foundation.h>  @interface User : NSObject  - (void)loginWithUsername:(NSString *)username andPassword:(NSString *)password; - (void)logout; - (BOOL)userAuthenticated;  @end 

User.m

#import "User.h"  @implementation User  - (void)loginWithUsername:(NSString *)username andPassword:(NSString *)password{      // Validate user here with your implementation     // and notify the root controller     [[NSNotificationCenter defaultCenter] postNotificationName:@"loginActionFinished" object:self userInfo:nil]; }  - (void)logout{     // Here you can delete the account }  - (BOOL)userAuthenticated {      // This variable is only for testing     // Here you have to implement a mechanism to manipulate this     BOOL auth = NO;      if (auth) {         return YES;     }      return NO; } 

3. Create a new controller RootViewController and connected with the first view, where login button live. Add also a Storyboard ID: "initialView".

RootViewController.h

#import <UIKit/UIKit.h> #import "LoginViewController.h"  @protocol LoginViewProtocol <NSObject>  - (void)dismissAndLoginView;  @end  @interface RootViewController : UIViewController  @property (nonatomic, weak) id <LoginViewProtocol> delegate; @property (nonatomic, retain) LoginViewController *loginView;   @end 

RootViewController.m

#import "RootViewController.h"  @interface RootViewController ()  @end  @implementation RootViewController  @synthesize loginView;  - (void)viewDidLoad {     [super viewDidLoad];     // Do any additional setup after loading the view, typically from a nib. }  - (void)didReceiveMemoryWarning {     [super didReceiveMemoryWarning];     // Dispose of any resources that can be recreated. }  - (IBAction)loginBtnPressed:(id)sender {      [[NSNotificationCenter defaultCenter] addObserver:self                                              selector:@selector(loginActionFinished:)                                                  name:@"loginActionFinished"                                                object:loginView];  }  #pragma mark - Dismissing Delegate Methods  -(void) loginActionFinished:(NSNotification*)notification {      AppDelegate *authObj = (AppDelegate*)[[UIApplication sharedApplication] delegate];     authObj.authenticated = YES;      [self dismissLoginAndShowProfile]; }  - (void)dismissLoginAndShowProfile {     [self dismissViewControllerAnimated:NO completion:^{         UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];         UITabBarController *tabView = [storyboard instantiateViewControllerWithIdentifier:@"profileView"];         [self presentViewController:tabView animated:YES completion:nil];     }];   }  @end 

4. Create a new controller LoginViewController and connected with the login view.

LoginViewController.h

#import <UIKit/UIKit.h> #import "User.h"  @interface LoginViewController : UIViewController 

LoginViewController.m

#import "LoginViewController.h" #import "AppDelegate.h"  - (void)viewDidLoad {     [super viewDidLoad]; }  - (IBAction)submitBtnPressed:(id)sender {     User *userObj = [[User alloc] init];      // Here you can get the data from login form     // and proceed to authenticate process     NSString *username = @"username retrieved through login form";     NSString *password = @"password retrieved through login form";     [userObj loginWithUsername:username andPassword:password]; }  @end 

5. At the end add a new controller ProfileViewController and connected with the profile view in the tabViewController.

ProfileViewController.h

#import <UIKit/UIKit.h>  @interface ProfileViewController : UIViewController  @end 

ProfileViewController.m

#import "ProfileViewController.h" #import "RootViewController.h" #import "AppDelegate.h" #import "User.h"  @interface ProfileViewController ()  @end  @implementation ProfileViewController  - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];     if (self) {         // Custom initialization     }     return self; }  - (void)viewDidLoad {     [super viewDidLoad];  }  - (void) viewWillAppear:(BOOL)animated {     [super viewWillAppear:animated];      if(![(AppDelegate*)[[UIApplication sharedApplication] delegate] authenticated]) {          UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];          RootViewController *initView =  (RootViewController*)[storyboard instantiateViewControllerWithIdentifier:@"initialView"];         [initView setModalPresentationStyle:UIModalPresentationFullScreen];         [self presentViewController:initView animated:NO completion:nil];     } else{         // proceed with the profile view     } }  - (void)didReceiveMemoryWarning {     [super didReceiveMemoryWarning];     // Dispose of any resources that can be recreated. }  - (IBAction)logoutAction:(id)sender {     User *userObj = [[User alloc] init];    [userObj logout];     AppDelegate *authObj = (AppDelegate*)[[UIApplication sharedApplication] delegate];    authObj.authenticated = NO;     UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];     RootViewController *initView =  (RootViewController*)[storyboard instantiateViewControllerWithIdentifier:@"initialView"];    [initView setModalPresentationStyle:UIModalPresentationFullScreen];    [self presentViewController:initView animated:NO completion:nil];  }  @end 

LoginExample is a sample project for extra help.


Comments

Popular posts from this blog

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?