Các phương pháp hay nhất cho màn hình đăng nhập Storyboard, xử lý xóa dữ liệu khi đăng xuất

292
Trevor Gehman 2013-11-14 09:07.

Tôi đang tạo ứng dụng iOS bằng Bảng phân cảnh. Bộ điều khiển chế độ xem gốc là Bộ điều khiển Thanh Tab. Tôi đang tạo quy trình đăng nhập / đăng xuất và nó hầu như hoạt động tốt, nhưng tôi gặp một số vấn đề. Tôi cần biết cách TỐT NHẤT để thiết lập tất cả những điều này.

Tôi muốn hoàn thành những điều sau:

  1. Hiển thị màn hình đăng nhập lần đầu tiên ứng dụng được khởi chạy. Khi họ đăng nhập, hãy chuyển đến tab đầu tiên của Bộ điều khiển thanh tab.
  2. Bất kỳ lúc nào họ khởi chạy ứng dụng sau đó, hãy kiểm tra xem họ đã đăng nhập chưa và chuyển thẳng đến tab đầu tiên của Bộ điều khiển thanh tab gốc.
  3. Khi họ nhấp vào nút đăng xuất theo cách thủ công, hiển thị màn hình đăng nhập và xóa tất cả dữ liệu khỏi bộ điều khiển chế độ xem.

Những gì tôi đã làm cho đến nay là đặt bộ điều khiển chế độ xem gốc thành Bộ điều khiển thanh tab và tạo một segue tùy chỉnh cho bộ điều khiển chế độ xem Đăng nhập của tôi. Bên trong lớp Bộ điều khiển thanh tab của mình, tôi kiểm tra xem chúng đã được đăng nhập bên trong viewDidAppearphương thức chưa và thực hiện segue:[self performSegueWithIdentifier:@"pushLogin" sender:self];

Tôi cũng thiết lập một thông báo về thời điểm cần thực hiện hành động đăng xuất: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutAccount) name:@"logoutAccount" object:nil];

Sau khi đăng xuất, tôi xóa thông tin xác thực khỏi Chuỗi khóa, chạy [self setSelectedIndex:0]và thực hiện xác minh để hiển thị lại bộ điều khiển chế độ xem đăng nhập.

Tất cả điều này đều hoạt động tốt, nhưng tôi tự hỏi: logic này có nên nằm trong AppDelegate không? Tôi cũng có hai vấn đề:

  • Lần đầu tiên họ khởi chạy ứng dụng , Bộ điều khiển thanh tab sẽ hiển thị ngắn gọn trước khi thực hiện phân tích. Tôi đã thử di chuyển mã sang viewWillAppearnhưng segue sẽ không hoạt động sớm như vậy.
  • Khi họ đăng xuất, tất cả dữ liệu vẫn nằm trong tất cả các bộ điều khiển chế độ xem. Nếu họ đăng nhập vào tài khoản mới, dữ liệu tài khoản cũ vẫn hiển thị cho đến khi họ làm mới. Tôi cần một cách để xóa điều này dễ dàng khi đăng xuất.

Tôi sẵn sàng làm lại điều này. Tôi đã cân nhắc việc đặt màn hình đăng nhập làm bộ điều khiển chế độ xem gốc hoặc tạo bộ điều khiển điều hướng trong AppDelegate để xử lý mọi thứ ... Tôi chỉ không chắc phương pháp tốt nhất là gì vào thời điểm này.

12 answers

313
bhavya kothari 2014-02-19 20:45.

Trong ứng dụng của bạnDelegate.m bên trong didFinishLaunchingWithOptions của bạn

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

Trong tệp SignUpViewController.m

- (IBAction)actionSignup:(id)sender
{
    AppDelegate *appDelegateTemp = [[UIApplication sharedApplication]delegate];

    appDelegateTemp.window.rootViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
}

Trong tệp 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;

}

Phiên bản Swift 4

didFinishLaunchingWithOptions trong ủy quyền ứng dụng giả sử bộ điều khiển chế độ xem ban đầu của bạn là bộ điều khiển đã đăng nhập trong TabbarController.

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

    return true

Trong Đăng ký bộ điều khiển chế độ xem:

@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
97
Trevor Gehman 2014-02-20 08:27.

Đây là những gì tôi đã làm để hoàn thành mọi thứ. Điều duy nhất bạn cần xem xét ngoài điều này là (a) quy trình đăng nhập và (b) nơi bạn đang lưu trữ dữ liệu ứng dụng của mình (trong trường hợp này, tôi đã sử dụng một singleton).

Như bạn có thể thấy, bộ điều khiển chế độ xem gốc là Bộ điều khiển Tab Chính của tôi . Tôi đã làm điều này vì sau khi người dùng đăng nhập, tôi muốn ứng dụng khởi chạy trực tiếp đến tab đầu tiên. (Điều này tránh bất kỳ "nhấp nháy" nào trong đó chế độ xem đăng nhập hiển thị tạm thời.)

AppDelegate.m

Trong tệp này, tôi kiểm tra xem người dùng đã đăng nhập chưa. Nếu chưa, tôi đẩy bộ điều khiển chế độ xem đăng nhập. Tôi cũng xử lý quá trình đăng xuất, nơi tôi xóa dữ liệu và hiển thị chế độ xem đăng nhập.

- (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

Tại đây, nếu đăng nhập thành công, tôi chỉ cần loại bỏ chế độ xem và gửi thông báo.

-(void) loginWasSuccessful
{

     // Send notification
     [[NSNotificationCenter defaultCenter] postNotificationName:@"loginSuccessful" object:self];

     // Dismiss login screen
     [self dismissViewControllerAnimated:YES completion:nil];

}
20
Dimitris Bouzikas 2014-02-20 00:18.

EDIT: Thêm hành động đăng xuất.

1. Trước hết, hãy chuẩn bị tệp đại biểu ứng dụng

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. Tạo một lớp có tên là Người dùng.

Người dùng.h

#import <Foundation/Foundation.h>

@interface User : NSObject

- (void)loginWithUsername:(NSString *)username andPassword:(NSString *)password;
- (void)logout;
- (BOOL)userAuthenticated;

@end

Người dùng.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. Tạo một bộ điều khiển mới RootViewController và được kết nối với chế độ xem đầu tiên, nơi có nút đăng nhập. Thêm cả ID Bảng phân cảnh: "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. Tạo một bộ điều khiển mới LoginViewController và được kết nối với chế độ xem đăng nhập.

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. Cuối cùng, thêm một bộ điều khiển mới ProfileViewController và được kết nối với chế độ xem hồ sơ trong 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 là một dự án mẫu để được trợ giúp thêm.

16
derpoliuk 2015-06-06 01:03.

Tôi không thích câu trả lời của bhavya vì sử dụng AppDelegatebên trong Bộ điều khiển Chế độ xem và cài đặt rootViewControllerkhông có hoạt ảnh. Và câu trả lời của Trevor có vấn đề với bộ điều khiển chế độ xem nhấp nháy trên iOS8.

CẬP NHẬT 18/07/2015

AppDelegate bên trong View Controllers:

Việc thay đổi trạng thái AppDelegate (thuộc tính) bên trong bộ điều khiển chế độ xem sẽ phá vỡ tính đóng gói.

Hệ thống phân cấp đối tượng rất đơn giản trong mọi dự án iOS:

AppDelegate (sở hữu windowrootViewController)

ViewController (sở hữu view)

Các đối tượng từ trên cùng thay đổi đối tượng ở dưới cùng là được, bởi vì họ đang tạo ra chúng. Nhưng sẽ không ổn nếu các đối tượng ở phía dưới thay đổi các đối tượng ở trên cùng của chúng (Tôi đã mô tả một số lập trình cơ bản / nguyên tắc OOP: DIP (Nguyên tắc đảo ngược phụ thuộc: mô-đun cấp cao không được phụ thuộc vào mô-đun cấp thấp, nhưng chúng phải phụ thuộc vào sự trừu tượng) ).

Nếu bất kỳ đối tượng nào sẽ thay đổi bất kỳ đối tượng nào trong hệ thống phân cấp này, sớm hay muộn sẽ có một mớ hỗn độn trong mã. Với những dự án nhỏ thì có thể không sao nhưng với những dự án nhỏ thì không vui khi đào bới mớ hỗn độn này =]

CẬP NHẬT 18/07/2015

Tôi sao chép các hoạt ảnh của bộ điều khiển phương thức bằng cách sử dụng UINavigationController(tl; dr: kiểm tra dự án ).

Tôi đang sử dụng UINavigationControllerđể trình bày tất cả các bộ điều khiển trong ứng dụng của mình. Ban đầu, tôi hiển thị bộ điều khiển chế độ xem đăng nhập trong ngăn xếp điều hướng với hoạt ảnh đẩy / bật đơn giản. Tôi quyết định thay đổi nó thành phương thức với những thay đổi tối thiểu.

Làm thế nào nó hoạt động:

  1. Bộ điều khiển chế độ xem ban đầu (hoặc self.window.rootViewController) là UINavigationController với ProgressViewController là a rootViewController. Tôi đang hiển thị ProgressViewController vì DataModel có thể mất một thời gian để khởi tạo vì nó lấy đi ngăn xếp dữ liệu cốt lõi như trong bài viết này (tôi thực sự thích cách tiếp cận này).

  2. AppDelegate chịu trách nhiệm cập nhật trạng thái đăng nhập.

  3. DataModel xử lý đăng nhập / đăng xuất của người dùng và AppDelegate đang quan sát thuộc userLoggedIntính của nó thông qua KVO. Có thể cho rằng đây không phải là phương pháp tốt nhất để làm điều này nhưng nó phù hợp với tôi. (Tại sao KVO là xấu, bạn có thể kiểm tra trong này hoặc bài viết này (Tại sao không sử dụng thông báo? Phần).

  4. ModalDismissAnimator và ModalPresentAnimator được sử dụng để tùy chỉnh hoạt ảnh đẩy mặc định.

Cách logic hoạt hình hoạt động:

  1. AppDelegate tự đặt mình là đại biểu của self.window.rootViewController(là UINavigationController).

  2. AppDelegate trả về một trong các trình hoạt họa -[AppDelegate navigationController:animationControllerForOperation:fromViewController:toViewController:]nếu cần thiết.

  3. Hoạt hình thực hiện -transitionDuration:-animateTransition:phương pháp. -[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]];
         }];
    }
    

Dự án thử nghiệm là ở đây .

11
Harry Bloom 2017-05-19 06:44.

Đây là giải pháp Swifty của tôi cho bất kỳ người xem nào trong tương lai.

1) Tạo giao thức để xử lý cả chức năng đăng nhập và đăng xuất:

protocol LoginFlowHandler {
    func handleLogin(withWindow window: UIWindow?)
    func handleLogout(withWindow window: UIWindow?)
}

2) Mở rộng giao thức đã nói và cung cấp chức năng tại đây để đăng xuất:

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) Sau đó, tôi có thể phù hợp AppDelegate của mình với giao thức LoginFlowHandler và gọi handleLoginkhi khởi động:

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
    }

}

Từ đây, phần mở rộng giao thức của tôi sẽ xử lý logic hoặc xác định xem liệu người dùng có đăng nhập / đăng xuất hay không, và sau đó thay đổi rootViewController của Windows cho phù hợp!

8
Mihado 2015-12-10 12:14.

KHÔNG khuyến khích thực hiện việc này từ đại biểu ứng dụng. AppDelegate quản lý vòng đời ứng dụng liên quan đến khởi chạy, tạm ngừng, chấm dứt, v.v. Tôi khuyên bạn nên làm điều này từ bộ điều khiển chế độ xem ban đầu của bạn trong viewDidAppear. Bạn có thể self.presentViewControllerself.dismissViewControllertừ bộ điều khiển chế độ xem đăng nhập. Lưu trữ một boolkhóa NSUserDefaultsđể xem liệu nó có đang chạy lần đầu tiên hay không.

6
iAleksandr 2018-07-09 14:07.

Sau khi tạo LoginViewControllerTabBarController , chúng ta cần thêm một StoryboardID là “ loginViewController ” và “ tabBarController ” tương ứng.

Sau đó, tôi muốn tạo cấu trúc Constant :

struct Constants {
    struct StoryboardID {
        static let signInViewController = "SignInViewController"
        static let mainTabBarController = "MainTabBarController"
    }

    struct kUserDefaults {
        static let isSignIn = "isSignIn"
    }
}

Trong LoginViewController, thêm IBAction :

@IBAction func tapSignInButton(_ sender: UIButton) {
    UserDefaults.standard.set(true, forKey: Constants.kUserDefaults.isSignIn)
    Switcher.updateRootViewController()
}

Trong ProfileViewController, thêm IBAction :

@IBAction func tapSignOutButton(_ sender: UIButton) {
    UserDefaults.standard.set(false, forKey: Constants.kUserDefaults.isSignIn)
    Switcher.updateRootViewController()
}

Trong AppDelegate, thêm dòng mã trong didFinishLaunchingWithOptions :

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    Switcher.updateRootViewController()

    return true
}

Cuối cùng tạo lớp Switcher :

import UIKit

class Switcher {

    static func updateRootViewController() {

        let status = UserDefaults.standard.bool(forKey: Constants.kUserDefaults.isSignIn)
        var rootViewController : UIViewController?

        #if DEBUG
        print(status)
        #endif

        if (status == true) {
            let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
            let mainTabBarController = mainStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardID.mainTabBarController) as! MainTabBarController
            rootViewController = mainTabBarController
        } else {
            let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
            let signInViewController = mainStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardID.signInViewController) as! SignInViewController
            rootViewController = signInViewController
        }

        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.window?.rootViewController = rootViewController

    }

}

Đó là tất cả!

5
Mahbub Morshed 2016-03-08 01:47.

Trong Xcode 7, bạn có thể có nhiều StoryBoards. Sẽ tốt hơn nếu bạn có thể giữ luồng Đăng nhập trong một bảng phân cảnh riêng.

Điều này có thể được thực hiện bằng cách sử dụng CHỌN VIEWCONTROLLER> Editor> Refactor to Storyboard

Và đây là phiên bản Swift để đặt chế độ xem là RootViewContoller-

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    appDelegate.window!.rootViewController = newRootViewController

    let rootViewController: UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("LoginViewController")
3
Thorsten 2014-02-19 19:19.

Tôi sử dụng cái này để kiểm tra lần khởi chạy đầu tiên:

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

(nếu người dùng xóa ứng dụng và cài đặt lại, nó được tính như lần khởi chạy đầu tiên)

Trong AppDelegate, tôi kiểm tra lần khởi chạy đầu tiên và tạo bộ điều khiển điều hướng với màn hình đăng nhập (đăng nhập và đăng ký), tôi đặt ở trên cửa sổ chính hiện tại:

[self.window makeKeyAndVisible];

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

Vì điều này nằm trên bộ điều khiển chế độ xem thông thường nên nó độc lập với phần còn lại của ứng dụng và bạn chỉ có thể loại bỏ bộ điều khiển chế độ xem nếu bạn không cần nó nữa. Và bạn cũng có thể trình bày chế độ xem theo cách này, nếu người dùng nhấn một nút theo cách thủ công.

BTW: Tôi lưu dữ liệu đăng nhập từ người dùng của mình như sau:

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

Đối với đăng xuất: Tôi đã chuyển khỏi CoreData (quá chậm) và sử dụng NSArrays và NSDictionaries để quản lý dữ liệu của mình ngay bây giờ. Đăng xuất chỉ có nghĩa là làm trống các mảng và từ điển đó. Ngoài ra, tôi đảm bảo đặt dữ liệu của mình trong viewWillAppear.

Đó là nó.

0
amb 2014-01-09 04:36.

Tôi cũng đang ở trong tình huống giống như bạn và giải pháp mà tôi tìm thấy để làm sạch dữ liệu là xóa tất cả nội dung CoreData mà bộ điều khiển chế độ xem của tôi dựa vào để rút ra thông tin. Nhưng tôi vẫn thấy cách tiếp cận này rất tệ, tôi nghĩ rằng một cách thanh lịch hơn để làm điều này có thể được thực hiện mà không có bảng phân cảnh và chỉ sử dụng mã để quản lý chuyển đổi giữa các bộ điều khiển chế độ xem.

Tôi đã tìm thấy dự án này tại Github thực hiện tất cả những thứ này chỉ bằng mã và nó khá dễ hiểu. Họ sử dụng menu bên giống như Facebook và những gì họ làm là thay đổi bộ điều khiển chế độ xem trung tâm tùy thuộc vào việc người dùng có đăng nhập hay không. Khi người dùng đăng xuất, appDelegatexóa dữ liệu khỏi CoreData và đặt lại bộ điều khiển chế độ xem chính vào màn hình đăng nhập.

0
Jithin 2018-05-25 21:11.

Tôi gặp sự cố tương tự cần giải quyết trong một ứng dụng và tôi đã sử dụng phương pháp sau. Tôi đã không sử dụng thông báo để xử lý điều hướng.

Tôi có ba bảng phân cảnh trong ứng dụng.

  1. Bảng phân cảnh màn hình Splash - để khởi chạy ứng dụng và kiểm tra xem người dùng đã đăng nhập chưa
  2. Bảng phân cảnh đăng nhập - để xử lý luồng đăng nhập của người dùng
  3. Bảng phân cảnh của thanh tab - để hiển thị nội dung ứng dụng

Bảng phân cảnh ban đầu của tôi trong ứng dụng là bảng phân cảnh màn hình Splash. Tôi có bộ điều khiển điều hướng làm gốc của đăng nhập và bảng phân cảnh thanh tab để xử lý các điều hướng của bộ điều khiển chế độ xem.

Tôi đã tạo một lớp Navigator để xử lý điều hướng ứng dụng và nó trông như thế này:

class Navigator: NSObject {

   static func moveTo(_ destinationViewController: UIViewController, from sourceViewController: UIViewController, transitionStyle: UIModalTransitionStyle? = .crossDissolve, completion: (() -> ())? = nil) {
       

       DispatchQueue.main.async {

           if var topController = UIApplication.shared.keyWindow?.rootViewController {

               while let presentedViewController = topController.presentedViewController {

                   topController = presentedViewController

               }

               
               destinationViewController.modalTransitionStyle = (transitionStyle ?? nil)!

               sourceViewController.present(destinationViewController, animated: true, completion: completion)

           }

       }

   }

}

Hãy xem xét các tình huống có thể xảy ra:

  • Khởi chạy ứng dụng đầu tiên; Màn hình Splash sẽ được tải ở nơi tôi kiểm tra xem người dùng đã đăng nhập chưa. Sau đó, màn hình đăng nhập sẽ được tải bằng cách sử dụng lớp Navigator như sau;

Vì tôi có bộ điều khiển điều hướng làm gốc, tôi khởi tạo bộ điều khiển điều hướng làm bộ điều khiển chế độ xem ban đầu.

let loginSB = UIStoryboard(name: "splash", bundle: nil)

let loginNav = loginSB.instantiateInitialViewcontroller() as! UINavigationController

Navigator.moveTo(loginNav, from: self)

Thao tác này sẽ xóa bảng phân cảnh slpash khỏi thư mục gốc của cửa sổ ứng dụng và thay thế bằng bảng phân cảnh đăng nhập.

Từ bảng phân cảnh đăng nhập, khi người dùng đã đăng nhập thành công, tôi lưu dữ liệu người dùng thành User Defaults và khởi tạo singleton UserData để truy cập chi tiết người dùng. Sau đó, bảng phân cảnh của thanh Tab được tải bằng cách sử dụng phương pháp điều hướng.

Let tabBarSB = UIStoryboard(name: "tabBar", bundle: nil)
let tabBarNav = tabBarSB.instantiateInitialViewcontroller() as! UINavigationController

Navigator.moveTo(tabBarNav, from: self)

Bây giờ người dùng đăng xuất khỏi màn hình cài đặt trong thanh tab. Tôi xóa tất cả dữ liệu người dùng đã lưu và điều hướng đến màn hình đăng nhập.

let loginSB = UIStoryboard(name: "splash", bundle: nil)

let loginNav = loginSB.instantiateInitialViewcontroller() as! UINavigationController

Navigator.moveTo(loginNav, from: self)
  • Người dùng đã đăng nhập và buộc giết ứng dụng

Khi người dùng khởi chạy ứng dụng, màn hình Splash sẽ được tải. Tôi kiểm tra xem người dùng đã đăng nhập và truy cập vào dữ liệu người dùng từ Mặc định của người dùng hay chưa. Sau đó khởi tạo singleton UserData và hiển thị thanh tab thay vì màn hình đăng nhập.

0
salanswift 2020-08-16 06:51.

Để cập nhật câu trả lời @iAleksandr cho Xcode 11, nguyên nhân gây ra sự cố do bộ cảnh.

  1. Thay thế
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = rootViewController

Với

Guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, hãy để sceneDelegate = windowScene.delegate là? SceneDelegate else {return
} sceneDelegate.window? .RootViewController = rootViewController

  1. gọi Switcher.updateRootViewcontroller trong ủy nhiệm Cảnh thay vì ủy nhiệm ứng dụng như thế này:

func scene (_ scene: UIScene, willConnectTo session: UISceneSession, tùy chọn kết nốiOptions: UIScene.ConnectionOptions) {

Switcher.updateRootViewController()

Guard let _ = (cảnh là? UIWindowScene) else {return}
}

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Một thương hiệu kế thừa khác có được cuộc sống mới khi những người chủ mới của Black Opal có được Hội chợ thời trang

Một thương hiệu kế thừa khác có được cuộc sống mới khi những người chủ mới của Black Opal có được Hội chợ thời trang

Desiree Rogers, trái, và Cheryl Mayberry McKissack Chuyển sang, Fenty Beauty và Pat McGrath, có một đế chế làm đẹp mới do phụ nữ làm chủ đang trỗi dậy. Sau thương vụ mua lại mỹ phẩm Black Opal vào tháng 9, đội ngũ quyền lực của Giám đốc điều hành công ty Desiree Rogers và Chủ tịch Cheryl Mayberry McKissack đã thông báo mua lại thương hiệu làm đẹp tiên phong Fashion Fair từ người sáng lập Johnson Publishing Company (JPC).

Ngoài việc trở nên vô nghĩa, các bên bộc lộ giới tính giờ đây đã trở nên chết người

Ngoài việc trở nên vô nghĩa, các bên bộc lộ giới tính giờ đây đã trở nên chết người

Đối với những người có quá nhiều thời gian, tiệc tiết lộ giới tính là một cách thú vị để không cần áp đặt những định kiến ​​hạn chế lên thai nhi trước một đối tượng bạn bè giả vờ quan tâm một cách lịch sự. Tuy nhiên, việc chỉ dựa vào những chiếc bánh nướng có màu nhân tạo để biểu thị một tiếng hoo-ha hoặc một đứa trẻ đi tè đã trở nên xa xỉ trong các bậc cha mẹ trên Instagram.

Kirstjen Nielsen đang cố gắng đổi mới bản thân với tư cách là một người phụ nữ 'nói ra sự thật cho sức mạnh'

Kirstjen Nielsen đang cố gắng đổi mới bản thân với tư cách là một người phụ nữ 'nói ra sự thật cho sức mạnh'

Hôm thứ Tư, cựu Bộ trưởng An ninh Nội địa Kirstjen Nielsen vì một lý do nào đó đã được đưa ra một diễn đàn để phát biểu tại Hội nghị thượng đỉnh Những người phụ nữ quyền lực nhất của Fortune. Và có thể đoán trước được, người phụ nữ giám sát các nỗ lực (đang diễn ra) của chính quyền Trump nhằm chia cắt các gia đình ở biên giới đã sử dụng thời gian của mình như một cơ hội để tự bảo vệ mình và tự nhận mình là người — và hãy hít thở sâu ở đây — “đã nói sự thật với quyền lực.

Toyota Racing Development sẽ cho ra mắt Supra 3000GT Concept, Massive Wing vào tháng tới

Toyota Racing Development sẽ cho ra mắt Supra 3000GT Concept, Massive Wing vào tháng tới

Vì thế hệ mới nhất của chiếc xe điều chỉnh được yêu thích trên thế giới hiện đã có mặt tại đây, nên chỉ có điều kiện là Toyota Racing Development sẽ đưa phiên bản Supra thế hệ thứ năm sửa đổi của riêng mình đến SEMA vào tháng tới. Toyota đã cho chúng tôi một gợi ý về những gì sẽ xảy ra trong tuần này: một chiếc Concept GR Supra 3000GT hiện đại.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Đường băng hạ cánh

Đường băng hạ cánh

Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Language