Best practices for Storyboard login screen, handling clearing of data upon logout

I’m building an iOS app using a Storyboard. The root view controller is a Tab Bar Controller. I’m creating the login/logout process, and it’s mostly working fine, but I’ve got a few issues. I need to know the BEST way to set all this up.

I want to accomplish the following:

  • Get 'Touch Drag Inside' Distance When Setting IBAction From Storyboard
  • Segue to another storyboard?
  • UItabbar item not showing storyboard reference
  • Dynamic TableView Cell Heights Incorrect Until After Scrolling (iOS 8) - full screenshots attached
  • ios pass values during a segue to another view
  • Bi-directional storyboard travel without stacking
    1. Show a login screen the first time the app is launched. When they login, go to the first tab of the Tab Bar Controller.
    2. Any time they launch the app after that, check if they are logged in, and skip straight to the first tab of the root Tab Bar Controller.
    3. When they manually click a logout button, show the login screen, and clear all the data from the view controllers.

    What I’ve done so far is set the root view controller to the Tab Bar Controller, and created a custom segue to my Login view controller. Inside my Tab Bar Controller class, I check whether they are logged in inside the viewDidAppear method, and a perform the segue: [self performSegueWithIdentifier:@"pushLogin" sender:self];

    I also setup a notification for when the logout action needs to be performed: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutAccount) name:@"logoutAccount" object:nil];

    Upon logout, I clear the credentials from the Keychain, run [self setSelectedIndex:0] and perform the segue to show the login view controller again.

    This all works fine, but I’m wondering: should this logic be in the AppDelegate? I also have two issues:

    • The first time they launch the app, the Tab Bar Controller shows briefly before the segue is performed. I’ve tried moving the code to viewWillAppear but the segue will not work that early.
    • When they logout, all the data is still inside all the view controllers. If they login to a new account, the old account data is still displayed until they refresh. I need a way to clear this easily on logout.

    I’m open to reworking this. I’ve considered making the login screen the root view controller, or creating a navigation controller in the AppDelegate to handle everything… I’m just not sure what the best method is at this point.

    12 Solutions Collect From Internet About “Best practices for Storyboard login screen, handling clearing of data upon logout”

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

    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.

    I didn’t like bhavya’s answer because of using AppDelegate inside View Controllers and setting rootViewController has no animation. And Trevor’s answer has issue with flashing view controller on iOS8.

    UPD 07/18/2015

    AppDelegate inside View Controllers:

    Changing AppDelegate state (properties) inside view controller breaks encapsulation.

    Very simple hierarchy of objects in every iOS project:

    AppDelegate (owns window and rootViewController)

    ViewController (owns view)

    It’s ok that objects from the top change objects at the bottom, because they are creating them. But it’s not ok if objects on the bottom change objects on top of them (I described some basic programming/OOP principle : DIP (Dependency Inversion Principle : high level module must not depend on the low level module, but they should depend on abstractions)).

    If any object will change any object in this hierarchy, sooner or later there will be a mess in the code. It might be ok on the small projects but it’s no fun to dig through this mess on the bit projects =]

    UPD 07/18/2015

    I replicate modal controller animations using UINavigationController (tl;dr: check the project).

    I’m using UINavigationController to present all controllers in my app. Initially I displayed login view controller in navigation stack with plain push/pop animation. Than I decided to change it to modal with minimal changes.

    How it works:

    1. Initial view controller (or self.window.rootViewController) is UINavigationController with ProgressViewController as a rootViewController. I’m showing ProgressViewController because DataModel can take some time to initialize because it inits core data stack like in this article (I really like this approach).

    2. AppDelegate is responsible for getting login status updates.

    3. DataModel handles user login/logout and AppDelegate is observing it’s userLoggedIn property via KVO. Arguably not the best method to do this but it works for me. (Why KVO is bad, you can check in this or this article (Why Not Use Notifications? part).

    4. ModalDismissAnimator and ModalPresentAnimator are used to customize default push animation.

    How animators logic works:

    1. AppDelegate sets itself as a delegate of self.window.rootViewController (which is UINavigationController).

    2. AppDelegate returns one of animators in -[AppDelegate navigationController:animationControllerForOperation:fromViewController:toViewController:] if necessary.

    3. Animators implement -transitionDuration: and -animateTransition: methods. -[ModalPresentAnimator animateTransition:]:

      - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
      {
          UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
          [[transitionContext containerView] addSubview:toViewController.view];
          CGRect frame = toViewController.view.frame;
          CGRect toFrame = frame;
          frame.origin.y = CGRectGetHeight(frame);
          toViewController.view.frame = frame;
          [UIView animateWithDuration:[self transitionDuration:transitionContext]
                           animations:^
           {
               toViewController.view.frame = toFrame;
           } completion:^(BOOL finished)
           {
               [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
           }];
      }
      

    Test project is here.

    Doing this from the app delegate is NOT recommended. AppDelegate manages the app life cycle that relate to launching, suspending, terminating and so on. I suggest doing this from your initial view controller in the viewDidAppear. You can self.presentViewController and self.dismissViewController from the login view controller. Store a bool key in NSUserDefaults to see if it’s launching for the first time.

    In Xcode 7 you can have multiple storyBoards. It will be better if you can keep the Login flow in a separate storyboard.

    This can be done using SELECT VIEWCONTROLLER > Editor > Refactor to Storyboard

    And here is the Swift version for setting a view as the RootViewContoller-

        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.window!.rootViewController = newRootViewController
    
        let rootViewController: UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("LoginViewController")
    

    Here’s my Swifty solution for any future onlookers.

    1) Create a protocol to handle both login and logout functions:

    protocol LoginFlowHandler {
        func handleLogin()
        func handleLogout()
    }
    

    2) Extend said protocol and provide the functionality here for logging out:

    extension LoginFlowHandler {
    
        func handleLogin(withWindow window: UIWindow?) {
    
            if let _ = AppState.shared.currentUserId {
                //User has logged in before, cache and continue
                self.showMainApp(withWindow: window)
            } else {
                //No user information, show login flow
                self.showLogin(withWindow: window)
            }
        }
    
        func handleLogout(withWindow window: UIWindow?) {
    
            AppState.shared.signOut()
    
            showLogin(withWindow: window)
        }
    
        func showLogin(withWindow window: UIWindow?) {
            window?.subviews.forEach { $0.removeFromSuperview() }
            window?.rootViewController = nil
            window?.rootViewController = R.storyboard.login.instantiateInitialViewController()
            window?.makeKeyAndVisible()
        }
    
        func showMainApp(withWindow window: UIWindow?) {
            window?.rootViewController = nil
            window?.rootViewController = R.storyboard.mainTabBar.instantiateInitialViewController()
            window?.makeKeyAndVisible()
        }
    }
    

    3) Then I can conform my AppDelegate to the LoginFlowHandler protocol, and call handleLogin on startup:

    class AppDelegate: UIResponder, UIApplicationDelegate, LoginFlowHandler {
    
        var window: UIWindow?
    
    
         func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
                window = UIWindow.init(frame: UIScreen.main.bounds)
    
                initialiseServices()
    
                handleLogin(withWindow: window)
    
                return true
            }
    }
    

    From here, my protocol extension will handle the logic or determining if the user if logged in/out, and then change the windows rootViewController accordingly!

    I use this to check for first launch:

    - (NSInteger) checkForFirstLaunch
    {
        NSInteger result = 0; //no first launch
    
        // Get current version ("Bundle Version") from the default Info.plist file
        NSString *currentVersion = (NSString*)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
        NSArray *prevStartupVersions = [[NSUserDefaults standardUserDefaults] arrayForKey:@"prevStartupVersions"];
        if (prevStartupVersions == nil)
        {
            // Starting up for first time with NO pre-existing installs (e.g., fresh
            // install of some version)
            [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:currentVersion] forKey:@"prevStartupVersions"];
            result = 1; //first launch of the app
        } else {
            if (![prevStartupVersions containsObject:currentVersion])
            {
                // Starting up for first time with this version of the app. This
                // means a different version of the app was alread installed once
                // and started.
                NSMutableArray *updatedPrevStartVersions = [NSMutableArray arrayWithArray:prevStartupVersions];
                [updatedPrevStartVersions addObject:currentVersion];
                [[NSUserDefaults standardUserDefaults] setObject:updatedPrevStartVersions forKey:@"prevStartupVersions"];
                result = 2; //first launch of this version of the app
            }
        }
    
        // Save changes to disk
        [[NSUserDefaults standardUserDefaults] synchronize];
    
        return result;
    }
    

    (if the user deletes the app and re-installs it, it counts like a first launch)

    In the AppDelegate I check for first launch and create a navigation-controller with the login screens (login and register), which I put on top of the current main window:

    [self.window makeKeyAndVisible];
    
    if (firstLaunch == 1) {
        UINavigationController *_login = [[UINavigationController alloc] initWithRootViewController:loginController];
        [self.window.rootViewController presentViewController:_login animated:NO completion:nil];
    }
    

    As this is on top of the regular view controller it’s independent from the rest of your app and you can just dismiss the view controller, if you don’t need it anymore. And you can also present the view this way, if the user presses a button manually.

    BTW: I save the login-data from my users like this:

    KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"com.youridentifier" accessGroup:nil];
    [keychainItem setObject:password forKey:(__bridge id)(kSecValueData)];
    [keychainItem setObject:email forKey:(__bridge id)(kSecAttrAccount)];
    

    For the logout: I switched away from CoreData (too slow) and use NSArrays and NSDictionaries to manage my data now. Logout just means to empty those arrays and dictionaries. Plus I make sure to set my data in viewWillAppear.

    That’s it.

    I’m in the same situation as you and the solution I found for cleaning the data is deleting all the CoreData stuff that my view controllers rely on to draw it’s info. But I still found this approach to be very bad, I think that a more elegant way to do this can be accomplished without storyboards and using only code to manage the transitions between view controllers.

    I’ve found this project at Github that does all this stuff only by code and it’s quite easy to understand. They use a Facebook-like side menu and what they do is change the center view controller depending if the user is logged-in or not. When the user logs out the appDelegate removes the data from CoreData and sets the main view controller to the login screen again.

    Thanks bhavya’s solution.There have been two answers about swift, but those are not very intact. I have do that in the swift3.Below is the main code.

    In AppDelegate.swift

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
    
        // seclect the mainStoryBoard entry by whthere user is login.
        let userDefaults = UserDefaults.standard
    
        if let isLogin: Bool = userDefaults.value(forKey:Common.isLoginKey) as! Bool? {
            if (!isLogin) {
                self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LogIn")
            }
       }else {
            self.window?.rootViewController = mainStoryboard.instantiateViewController(withIdentifier: "LogIn")
       }
    
        return true
    }
    

    In SignUpViewController.swift

    @IBAction func userLogin(_ sender: UIButton) {
        //handle your login work
        UserDefaults.standard.setValue(true, forKey: Common.isLoginKey)
        let delegateTemp = UIApplication.shared.delegate
        delegateTemp?.window!?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Main")
    }
    

    In logOutAction function

    @IBAction func logOutAction(_ sender: UIButton) {
        UserDefaults.standard.setValue(false, forKey: Common.isLoginKey)
        UIApplication.shared.delegate?.window!?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
    }
    

    enter image description hereFirst, never do this in the AppDelegate. This is not its responsibility. Also, never swap out the root view controller on a running app! The first (root) view controller should call somewhere to check login state and present a login view controller if needed.

    Dismiss this once logged in.

    Note: You have to present from viewDidAppear in iOS because of the lifecycle. Animate if you wish and you could do some animation transition if you need the whiz bang.

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        if notLoggedIn {
          let vc = storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
          present(vc, animated: false)
        }
      }
    

    Inside the login view controller just dismiss as usual.

    enter image description here

    In App Delegate.m

     - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60)
                                                         forBarMetrics:UIBarMetricsDefault];
    
    NSString *identifier;
    BOOL isSaved = [[NSUserDefaults standardUserDefaults] boolForKey:@"loginSaved"];
    if (isSaved)
    {
        //identifier=@"homeViewControllerId";
        UIWindow* mainWindow=[[[UIApplication sharedApplication] delegate] window];
        UITabBarController *tabBarVC =
        [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"TabBarVC"];
        mainWindow.rootViewController=tabBarVC;
    }
    else
    {
    
    
        identifier=@"loginViewControllerId";
        UIStoryboard *    storyboardobj=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UIViewController *screen = [storyboardobj instantiateViewControllerWithIdentifier:identifier];
    
        UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:screen];
    
        self.window.rootViewController = navigationController;
        [self.window makeKeyAndVisible];
    
    }
    
    return YES;
    

    }

    view controller.m
    In view did load

    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    UIBarButtonItem* barButton = [[UIBarButtonItem alloc] initWithTitle:@"Logout" style:UIBarButtonItemStyleDone target:self action:@selector(logoutButtonClicked:)];
    [self.navigationItem setLeftBarButtonItem:barButton];
    

    }

    In logout button action

    -(void)logoutButtonClicked:(id)sender{
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Alert" message:@"Do you want to logout?" preferredStyle:UIAlertControllerStyleAlert];
    
        [alertController addAction:[UIAlertAction actionWithTitle:@"Logout" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
               NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        [defaults setBool:NO forKey:@"loginSaved"];
               [[NSUserDefaults standardUserDefaults] synchronize];
          AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
        UIStoryboard *    storyboardobj=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
        UIViewController *screen = [storyboardobj instantiateViewControllerWithIdentifier:@"loginViewControllerId"];
        [appDelegate.window setRootViewController:screen];
    }]];
    
    
    [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        [self dismissViewControllerAnimated:YES completion:nil];
    }]];
    
    dispatch_async(dispatch_get_main_queue(), ^ {
        [self presentViewController:alertController animated:YES completion:nil];
    });}