แนวทางปฏิบัติที่ดีที่สุดสำหรับหน้าจอเข้าสู่ระบบ Storyboard จัดการการล้างข้อมูลเมื่อออกจากระบบ


290

ฉันกำลังสร้างแอพ iOS โดยใช้สตอรี่บอร์ด ตัวควบคุมมุมมองรูทเป็นตัวควบคุมแถบแท็บ ฉันกำลังสร้างกระบวนการเข้าสู่ระบบ / ออกจากระบบและส่วนใหญ่ทำงานได้ดี แต่ฉันมีปัญหาเล็กน้อย ฉันจำเป็นต้องรู้วิธีที่ดีที่สุดในการตั้งค่าทั้งหมดนี้

ฉันต้องการทำสิ่งต่อไปนี้ให้สำเร็จ:

  1. แสดงหน้าจอเข้าสู่ระบบในครั้งแรกที่เปิดตัวแอพ เมื่อเข้าสู่ระบบให้ไปที่แท็บแรกของ Tab Bar Controller
  2. เมื่อใดก็ตามที่พวกเขาเปิดแอพหลังจากนั้นให้ตรวจสอบว่าพวกเขาเข้าสู่ระบบและข้ามตรงไปที่แท็บแรกของตัวควบคุมแถบแท็บราก
  3. เมื่อพวกเขาคลิกปุ่มออกจากระบบด้วยตนเองแสดงหน้าจอเข้าสู่ระบบและล้างข้อมูลทั้งหมดจากตัวควบคุมมุมมอง

สิ่งที่ฉันได้ทำไปแล้วคือการตั้งค่าตัวควบคุมมุมมองรูทเป็นตัวควบคุมแถบของแท็บและสร้างส่วนต่อขยายที่กำหนดเองให้กับตัวควบคุมมุมมองล็อกอินของฉัน ในคลาส Tab Bar Controller ของฉันฉันตรวจสอบว่าพวกเขาเข้าสู่ระบบภายในviewDidAppearวิธีการและดำเนินการต่อ:[self performSegueWithIdentifier:@"pushLogin" sender:self];

ฉันยังตั้งค่าการแจ้งเตือนเมื่อต้องมีการดำเนินการล็อกเอาต์: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutAccount) name:@"logoutAccount" object:nil];

เมื่อออกจากระบบฉันล้างข้อมูลรับรองจาก Keychain เรียกใช้[self setSelectedIndex:0]และดำเนินการต่อเพื่อแสดงตัวควบคุมมุมมองการเข้าสู่ระบบอีกครั้ง

ทั้งหมดนี้ใช้งานได้ดี แต่ฉันสงสัยว่า: ตรรกะนี้ควรอยู่ใน AppDelegate หรือไม่ ฉันยังมีสองประเด็น:

  • ครั้งแรกที่พวกเขาเปิดแอปตัวควบคุมแถบของแท็บจะแสดงสั้น ๆ ก่อนที่จะดำเนินการต่อ ฉันได้ลองย้ายรหัสไปแล้วviewWillAppearแต่การทำต่อไม่ได้ผล
  • เมื่อพวกเขาออกจากระบบข้อมูลทั้งหมดจะยังคงอยู่ในตัวควบคุมมุมมองทั้งหมด หากพวกเขาลงชื่อเข้าใช้บัญชีใหม่ข้อมูลบัญชีเก่าจะยังคงปรากฏจนกว่าพวกเขาจะรีเฟรช ฉันต้องการวิธีล้างข้อมูลนี้อย่างง่ายดายเมื่อออกจากระบบ

ฉันเปิดให้ทำงานใหม่ได้ ฉันได้พิจารณาให้หน้าจอการเข้าสู่ระบบเป็นตัวควบคุมรูทวิวหรือสร้างตัวควบคุมการนำทางใน AppDelegate เพื่อจัดการทุกอย่าง ... ฉันแค่ไม่แน่ใจว่าวิธีการที่ดีที่สุดคืออะไร ณ จุดนี้


คุณแสดงตัวควบคุมมุมมองการเข้าสู่ระบบเป็น modal หรือไม่
vokilam

@TrevorGehman - สามารถเพิ่มรูปกระดานเรื่องราวของคุณ
rohan k shah

ฉันส่งคำตอบพร้อมรายละเอียดเกี่ยวกับสิ่งที่ฉันทำ มันคล้ายกับคำตอบอื่น ๆ ที่มีให้โดยเฉพาะ @bhavya kothari
เทรเวอร์ Gehman

สำหรับการนำเสนอหน้าจอเข้าสู่ระบบAuthNavigationอาจมีประโยชน์ มันจัดงานนำเสนอของหน้าจอเข้าสู่ระบบหากจำเป็นและยังสนับสนุนการเข้าสู่ระบบอัตโนมัติ
Codey

หนึ่งในปัญหาพื้นฐานที่แก้ไขได้เกือบทุกครั้ง แต่ในขณะเดียวกันก็รู้สึกว่าสามารถทำได้ดีกว่า
amar

คำตอบ:


311

กระดานเรื่องราวของคุณควรมีลักษณะเช่นนี้

ใน appDelegate.m ของคุณภายใน 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;
}

ในไฟล์ SignUpViewController.m

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

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

ในไฟล์ 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

didFinishLaunchingWithOptions ในตัวแทนแอปสมมติว่าตัวควบคุมมุมมองเริ่มต้นของคุณคือลงชื่อใน TabbarController

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

    return true

ในตัวควบคุมการลงทะเบียนดู:

@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

คุณลืมลบการรับรองความถูกต้อง bool จาก userDefaults หลังจากออกจากระบบ
CodeLover

28
-1 สำหรับการใช้AppDelegateภายในUIViewControllerและการตั้งค่าที่window.rootViewControllerนั่น ฉันไม่คิดว่านี่เป็น "แนวปฏิบัติที่ดีที่สุด"
derpoliuk

2
ไม่ต้องการให้-1โดยไม่โพสต์คำตอบ: stackoverflow.com/a/30664935/1226304
derpoliuk

1
ฉันกำลังพยายามทำสิ่งนี้อย่างรวดเร็วบน IOS8 แต่ฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อแอพเริ่มทำงานและหน้าจอเข้าสู่ระบบแสดงขึ้น: "การโทรที่ไม่สมดุลเพื่อเปลี่ยน / เริ่มต้นลักษณะสิ้น" ฉันสังเกตเห็นว่าเมื่อแอพโหลดหน้าจอเข้าสู่ระบบจะแสดง แต่ยังมีแท็บแรกบนตัวควบคุมแถบแท็บกำลังโหลด ยืนยันสิ่งนี้ผ่าน println () ใน viewdidload ข้อเสนอแนะ?
Alex Lacayo

1
บิงโก! -2 -1 AppDelegateภายในUIViewController-1 NSUserDefaultsสำหรับการจัดเก็บคีย์เข้าสู่ระบบใน มันไม่ปลอดภัยมากสำหรับข้อมูลประเภทนั้น!
skywinder

97

นี่คือสิ่งที่ฉันทำเพื่อทำให้ทุกอย่างสำเร็จ สิ่งเดียวที่คุณต้องพิจารณาเพิ่มเติมคือ (a) กระบวนการเข้าสู่ระบบและ (b) ที่คุณจัดเก็บข้อมูลแอปของคุณ (ในกรณีนี้ฉันใช้ซิงเกิล)

บอร์ดโครงเรื่องแสดงตัวควบคุมมุมมองการเข้าสู่ระบบและตัวควบคุมแท็บหลัก

อย่างที่คุณเห็นตัวควบคุมมุมมองรูทเป็นตัวควบคุมแท็บหลักของฉันแท็บหลักควบคุมฉันทำเช่นนี้เพราะหลังจากผู้ใช้ลงชื่อเข้าใช้ฉันต้องการให้แอปเปิดใช้งานไปยังแท็บแรกโดยตรง (สิ่งนี้จะหลีกเลี่ยง "การสั่นไหว" ที่มุมมองการเข้าสู่ระบบแสดงชั่วคราว)

AppDelegate.m

ในไฟล์นี้ฉันจะตรวจสอบว่าผู้ใช้เข้าสู่ระบบแล้วถ้าไม่ฉันผลักดันตัวควบคุมมุมมองเข้าสู่ระบบ ฉันยังจัดการกระบวนการออกจากระบบที่ฉันล้างข้อมูลและแสดงมุมมองเข้าสู่ระบบ

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

ที่นี่หากการเข้าสู่ระบบสำเร็จฉันเพียงแค่ยกเลิกมุมมองและส่งการแจ้งเตือน

-(void) loginWasSuccessful
{

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

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

}

2
คุณใช้การแจ้งเตือนเพื่ออะไร
กบฏ

1
@BFeher ถูกต้อง ฉันใช้การแจ้งเตือนเพื่อทริกเกอร์การดึงข้อมูลใหม่ คุณสามารถใช้มันเพื่อทำสิ่งที่คุณต้องการ แต่ในกรณีของฉันฉันต้องได้รับแจ้งว่าการเข้าสู่ระบบนั้นประสบความสำเร็จและต้องการข้อมูลใหม่
Trevor Gehman

24
ใน iOS 8.1 (และอาจ 8.0 ยังไม่ได้ทดสอบ) สิ่งนี้ไม่ทำงานอย่างราบรื่นอีกต่อไป View Controller เริ่มต้นจะกะพริบชั่วครู่หนึ่ง
BFeher

7
มีวิธีนี้ในเวอร์ชั่น Swift หรือไม่?
Seano

9
@ จูเลียนใน iOS 8 ฉันแทนที่สองบรรทัด[self.window makeKeyAndVisible]; [self.window.rootViewController presentViewController:viewController animated:animated completion:nil];ด้วยself.window.rootViewController = viewController;เพื่อป้องกันการสั่นไหว เพื่อให้ภาพเคลื่อนไหวที่ห่ออยู่ใน[UIView transitionWithView...];
BFeher

20

แก้ไข:เพิ่มการกระทำออกจากระบบ

ป้อนคำอธิบายรูปภาพที่นี่

1.ก่อนอื่นเตรียมไฟล์มอบหมายแอพ

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.สร้างคลาสที่ชื่อผู้ใช้

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.สร้างคอนโทรลเลอร์ใหม่ RootViewController และเชื่อมต่อกับมุมมองแรกโดยที่ปุ่มล็อกอินอยู่ เพิ่ม 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.สร้างคอนโทรลเลอร์ใหม่ LoginViewController และเชื่อมต่อกับมุมมองล็อกอิน

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ในตอนท้ายเพิ่มคอนโทรลเลอร์ใหม่ ProfileViewController และเชื่อมต่อกับมุมมองโปรไฟล์ใน 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เป็นโครงการตัวอย่างสำหรับความช่วยเหลือเพิ่มเติม


3
ตัวอย่างโครงการช่วยผมมากที่จะเข้าใจแนวคิดของการเข้าสู่ระบบออกจากระบบ n .. ขอบคุณมาก :)
เดฟ

16

ฉันไม่ชอบคำตอบของ bhavya เนื่องจากการใช้AppDelegateภายในตัวควบคุมมุมมองและการตั้งค่าrootViewControllerไม่มีภาพเคลื่อนไหว และคำตอบของ Trevor มีปัญหากับตัวควบคุมการกะพริบของ iOS8

UPD 07/18/2015

AppDelegate ภายใน View Controllers:

การเปลี่ยนสถานะ (คุณสมบัติ) ของ AppDelegate ภายในตัวควบคุมมุมมองแบ่งการห่อหุ้ม

ลำดับชั้นของวัตถุที่ง่ายมากในทุกโครงการ iOS:

AppDelegate (เป็นเจ้าของwindowและrootViewController)

ViewController (เป็นเจ้าของview)

มันก็โอเคที่วัตถุจากวัตถุเปลี่ยนแปลงชั้นนำที่อยู่ด้านล่างเพราะพวกเขากำลังสร้างพวกเขา แต่มันก็ไม่เป็นไรถ้าวัตถุที่อยู่ด้านล่างเปลี่ยนวัตถุที่อยู่ด้านบนของพวกเขา (ฉันอธิบายบางโปรแกรมพื้นฐาน / หลักการ OOP: กรมทรัพย์สินทางปัญญา (หลักการผกผันพึ่งพา: โมดูลระดับสูงจะต้องไม่ขึ้นอยู่กับโมดูลระดับต่ำ แต่พวกเขาควรขึ้นอยู่กับนามธรรม) )

หากวัตถุใด ๆ ที่จะเปลี่ยนวัตถุใด ๆ ในลำดับชั้นนี้ไม่ช้าก็เร็วจะมีความยุ่งเหยิงในรหัส มันอาจจะโอเคกับโปรเจคเล็ก ๆ แต่มันไม่สนุกเลยที่จะขุดคุ้ยเรื่องนี้ในโปรเจ็กต์บิต =]

UPD 07/18/2015

ฉันทำซ้ำภาพเคลื่อนไหวตัวควบคุมโมดอลโดยใช้UINavigationController(tl; dr: ตรวจสอบโครงการ )

ฉันใช้UINavigationControllerเพื่อแสดงตัวควบคุมทั้งหมดในแอพของฉัน ตอนแรกฉันแสดงตัวควบคุมมุมมองการเข้าสู่ระบบในกองการนำทางด้วยภาพเคลื่อนไหวแบบพุช / ป๊อปแบบธรรมดา กว่าฉันตัดสินใจที่จะเปลี่ยนเป็นคำกริยาที่มีการเปลี่ยนแปลงน้อยที่สุด

มันทำงานอย่างไร:

  1. ควบคุมมุมมองเริ่มต้น (หรือself.window.rootViewController) เป็น UINavigationController กับ ProgressViewController rootViewControllerเป็น ฉันกำลังแสดง ProgressViewController เพราะ DataModel อาจต้องใช้เวลาพอสมควรในการเริ่มต้นเพราะมันทำให้เกิด data stack หลักเหมือนกับในบทความนี้ (ฉันชอบวิธีนี้มาก)

  2. AppDelegate รับผิดชอบในการรับการอัพเดตสถานะการเข้าสู่ระบบ

  3. DataModel จัดการผู้ใช้เข้าสู่ระบบ / ออกจากระบบและ AppDelegate กำลังตรวจสอบuserLoggedInคุณสมบัติของมันผ่านทาง KVO อาจไม่ใช่วิธีที่ดีที่สุดในการทำสิ่งนี้ แต่มันก็ใช้ได้ผลสำหรับฉัน (ทำไม KVO ไม่ดีคุณสามารถตรวจสอบในนี้ หรือบทความนี้ (ทำไมไม่ใช้การแจ้งเตือน? บางส่วน)

  4. ModalDismissAnimator และ ModalPresentAnimator ใช้เพื่อกำหนดแอนิเมชั่นพุชแบบกำหนดเอง

ตรรกะของอนิเมเตอร์ทำงานอย่างไร:

  1. AppDelegate ตั้งค่าตัวเองเป็นตัวแทนของ self.window.rootViewController(ซึ่งคือ UINavigationController)

  2. AppDelegate ส่งคืนหนึ่งในแอนิเมชั่นใน-[AppDelegate navigationController:animationControllerForOperation:fromViewController:toViewController:]กรณีที่จำเป็น

  3. แอนิเมชั่นใช้-transitionDuration:และ-animateTransition:วิธีการ -[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]];
         }];
    }

โครงการทดสอบเป็นที่นี่


3
ส่วนตัวฉันไม่มีปัญหากับ View Controllers ที่รู้เกี่ยวกับAppDelegate(ฉันสนใจที่จะเข้าใจว่าทำไมคุณถึงทำ) - แต่ความคิดเห็นของคุณเกี่ยวกับการขาดภาพเคลื่อนไหวนั้นถูกต้องมาก ที่สามารถแก้ไขได้โดยคำตอบนี้: stackoverflow.com/questions/8053832/…
HughHughTeotl

2
@HughHughTeotl ขอบคุณสำหรับความคิดเห็นและลิงก์ ฉันปรับปรุงคำตอบของฉัน
derpoliuk

1
@derpoliuk จะเกิดอะไรขึ้นถ้าคอนโทรลเลอร์มุมมองพื้นฐานของฉันคือ UITabBarController ฉันไม่สามารถผลักดันมันใน UINavigationController
Giorgio

@ จอร์โจมันเป็นคำถามที่น่าสนใจฉันไม่ได้ใช้UITabBarControllerมานานมาก ฉันอาจเริ่มต้นด้วยวิธีการแบบหน้าต่างแทนที่จะจัดการมุมมองตัวควบคุม
derpoliuk

11

นี่คือทางออก Swifty ของฉันสำหรับผู้เข้าชมในอนาคตใด ๆ

1) สร้างโปรโตคอลเพื่อจัดการทั้งฟังก์ชั่นเข้าสู่ระบบและออกจากระบบ:

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

2) ขยายโปรโตคอลดังกล่าวและจัดเตรียมการทำงานที่นี่เพื่อออกจากระบบ:

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) จากนั้นฉันสามารถปฏิบัติตาม AppDelegate กับโปรโตคอล LoginFlowHandler และโทรhandleLoginเมื่อเริ่มต้น:

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
    }

}

จากที่นี่ส่วนขยายโปรโตคอลของฉันจะจัดการกับตรรกะหรือพิจารณาว่าผู้ใช้ถ้าเข้าสู่ระบบ / ออกแล้วเปลี่ยน Windows rootViewController Windows!


ถ้าไม่แน่ใจว่าฉันเป็นคนโง่ แต่ AppDelegate LoginFlowHandlerไม่เป็นไปตาม ฉันพลาดอะไรไปรึเปล่า? นอกจากนี้ฉันเดารหัสนี้จะจัดการการเข้าสู่ระบบเมื่อเริ่มต้นเท่านั้น ฉันจะจัดการออกจากระบบจากตัวควบคุมมุมมองได้อย่างไร
ลุค

@luke เนื่องจากมีการใช้ตรรกะทั้งหมดในส่วนขยายจึงไม่จำเป็นต้องใช้มันใน AppDelegate นั่นเป็นสิ่งที่ยอดเยี่ยมมากในส่วนขยายของโปรโตคอล
shannoga

1
ขออภัย @sirFunkenstine นั่นเป็นคลาสที่กำหนดเองที่ฉันสร้างขึ้นเพื่อแสดงตัวอย่างว่าจะตรวจสอบแคชแอพเพื่อตรวจสอบว่าผู้ใช้เข้าสู่ระบบก่อนหน้านี้หรือไม่ AppStateการใช้งานนี้จะขึ้นอยู่กับวิธีที่คุณบันทึกข้อมูลผู้ใช้ลงในดิสก์
Harry Bloom

@HarryBloom หนึ่งจะใช้handleLogoutฟังก์ชันได้อย่างไร
nithinisreddy

1
สวัสดี @nithinisreddy - ในการเรียกใช้ฟังก์ชัน handleLogout คุณจะต้องสอดคล้องกับคลาสที่คุณโทรจากถึงLoginFlowHandlerโปรโตคอล จากนั้นคุณจะได้รับขอบเขตเพื่อให้สามารถเรียกใช้วิธี handleLogout ดูขั้นตอนที่ 3 ของฉันสำหรับตัวอย่างของวิธีที่ฉันทำสำหรับคลาส AppDelegate
Harry Bloom

8

ไม่แนะนำให้ทำเช่นนี้จากตัวแทนแอป AppDelegate จัดการวงจรชีวิตของแอพที่เกี่ยวข้องกับการเปิดตัวการระงับการยกเลิกและอื่น ๆ viewDidAppearผมขอแนะนำให้ทำเช่นนี้จากตัวควบคุมมุมมองเริ่มต้นของคุณใน คุณสามารถself.presentViewControllerและself.dismissViewControllerจากตัวควบคุมมุมมองเข้าสู่ระบบ เก็บboolรหัสไว้ในNSUserDefaultsเพื่อดูว่ามีการเปิดตัวเป็นครั้งแรกหรือไม่


2
มุมมองควรปรากฏ (ผู้ใช้มองเห็นได้) ใน `viewDidAppear 'หรือไม่ สิ่งนี้จะยังคงสร้างการสั่นไหว
Mark13426

2
ไม่ใช่คำตอบ และ "เก็บคีย์บูลใน NSUserDefaults เพื่อดูว่ามันเปิดตัวเป็นครั้งแรกหรือไม่" เป็นสิ่งที่อันตรายมากสำหรับข้อมูลประเภทนั้น
skywinder

6

สร้าง ** LoginViewController ** และ ** TabBarController **

หลังจากสร้างLoginViewControllerและTabBarControllerเราต้องเพิ่ม StoryboardID เป็น“ loginViewController ” และ“ tabBarController ” ตามลำดับ

จากนั้นฉันต้องการสร้างโครงสร้างคงที่ :

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

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

ในLoginViewControllerเพิ่มIBAction :

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

ในProfileViewControllerเพิ่มIBAction :

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

ในAppDelegateเพิ่มบรรทัดของรหัสในdidFinishLaunchingWithOptions :

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

    Switcher.updateRootViewController()

    return true
}

ในที่สุดสร้างคลาส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

    }

}

นั้นคือทั้งหมด!


มีความแตกต่างใดที่ตัวควบคุมมุมมองเริ่มต้นในกระดานเรื่องราวหรือไม่ ในภาพที่เพิ่มเข้ามาฉันเห็นได้ว่าคุณมีตัวเลือก "is Initial View Controller" บนตัวควบคุมแถบแท็บ ใน AppDelegate u เปลี่ยนคอนโทรลเลอร์รูทดูหลักดังนั้นฉันเดาว่ามันไม่สำคัญเลยใช่ไหม?
ShadeToD

@iAleksandr โปรดอัปเดตคำตอบสำหรับ iOS 13. Coz ของ SceneDelegate คำตอบปัจจุบันไม่ทำงาน
Nitesh

5

ใน Xcode 7 คุณสามารถมีกระดานเรื่องราวหลายเรื่อง มันจะดีกว่านี้ถ้าคุณสามารถเก็บขั้นตอนการเข้าสู่ระบบไว้ในกระดานเรื่องราวแยกต่างหาก

สิ่งนี้สามารถทำได้โดยใช้ SELECT VIEWCONTROLLER> Editor> Refactor to Storyboard

และนี่คือเวอร์ชั่น Swift สำหรับตั้งค่ามุมมองเป็น RootViewContoller-

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

    let rootViewController: UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("LoginViewController")

3

ฉันใช้สิ่งนี้เพื่อตรวจสอบการเปิดตัวครั้งแรก:

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

(หากผู้ใช้ลบแอพและติดตั้งซ้ำจะนับเป็นการเปิดตัวครั้งแรก)

ใน AppDelegate ฉันจะตรวจสอบการเปิดตัวครั้งแรกและสร้างตัวควบคุมทิศทางด้วยหน้าจอเข้าสู่ระบบ (ล็อกอินและลงทะเบียน) ซึ่งฉันวางไว้ด้านบนของหน้าต่างหลักปัจจุบัน:

[self.window makeKeyAndVisible];

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

เนื่องจากนี่คือตัวควบคุมมุมมองปกติที่เป็นอิสระจากแอปที่เหลือของคุณและคุณสามารถยกเลิกตัวควบคุมมุมมองได้หากคุณไม่ต้องการมันอีกต่อไป และคุณยังสามารถนำเสนอมุมมองด้วยวิธีนี้หากผู้ใช้กดปุ่มด้วยตนเอง

BTW: ฉันบันทึกข้อมูลเข้าสู่ระบบจากผู้ใช้ของฉันเช่นนี้:

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

สำหรับการออกจากระบบ: ฉันเปลี่ยนจาก CoreData (ช้าเกินไป) และใช้ NSArrays และ NSDictionaries เพื่อจัดการข้อมูลของฉันทันที การออกจากระบบหมายถึงการล้างอาร์เรย์และพจนานุกรมเหล่านั้น นอกจากนี้ฉันต้องแน่ใจว่าตั้งค่าข้อมูลของฉันใน viewWillAppear

แค่นั้นแหละ.


0

ฉันอยู่ในสถานการณ์เดียวกับคุณและวิธีแก้ปัญหาที่ฉันพบในการล้างข้อมูลคือการลบข้อมูล CoreData ทั้งหมดที่ตัวควบคุมมุมมองของฉันใช้เพื่อดึงข้อมูล แต่ฉันก็ยังพบว่าวิธีการนี้แย่มากฉันคิดว่าวิธีที่ดีกว่าในการทำสิ่งนี้สามารถทำได้โดยไม่มีสตอรีบอร์ดและใช้รหัสเพียงเพื่อจัดการการเปลี่ยนระหว่างตัวควบคุมมุมมอง

ฉันพบโครงการนี้ที่ Github ซึ่งทำสิ่งทั้งหมดนี้ด้วยรหัสเท่านั้นและมันค่อนข้างเข้าใจง่าย พวกเขาใช้เมนูด้าน Facebook และสิ่งที่พวกเขาทำคือเปลี่ยนตัวควบคุมมุมมองกลางขึ้นอยู่กับว่าผู้ใช้เข้าสู่ระบบหรือไม่ เมื่อผู้ใช้ออกจากระบบappDelegateจะลบข้อมูลจาก CoreData และตั้งค่าตัวควบคุมมุมมองหลักเป็นหน้าจอเข้าสู่ระบบอีกครั้ง


0

ฉันมีปัญหาที่คล้ายกันเพื่อแก้ไขในแอพและฉันใช้วิธีการต่อไปนี้ ฉันไม่ได้ใช้การแจ้งเตือนเพื่อจัดการการนำทาง

ฉันมีกระดานเรื่องราวสามเรื่องในแอป

  1. Splash screen storyboard - สำหรับการเริ่มต้นแอพและตรวจสอบว่าผู้ใช้ลงชื่อเข้าใช้แล้ว
  2. ล็อกอินสตอรี่บอร์ด - สำหรับการจัดการโฟลว์การล็อกอินของผู้ใช้
  3. กระดานเรื่องราวแถบแท็บ - สำหรับแสดงเนื้อหาแอพ

กระดานเรื่องราวเริ่มต้นของฉันในแอปคือกระดานเรื่องราวบนหน้าจอ Splash ฉันมีตัวควบคุมการนำทางเป็นรากของกระดานเรื่องราวและแท็บแถบเพื่อจัดการการนำทางของตัวควบคุมมุมมอง

ฉันสร้างคลาสเนวิเกเตอร์เพื่อจัดการการนำทางแอพและมีลักษณะดังนี้:

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)

           }

       }

   }

}

ลองดูสถานการณ์ที่เป็นไปได้:

  • เปิดตัวแอปแรก หน้าจอเริ่มต้นจะถูกโหลดโดยที่ฉันตรวจสอบว่าผู้ใช้ลงชื่อเข้าใช้แล้วหน้าจอเข้าสู่ระบบจะถูกโหลดโดยใช้คลาสเนวิเกเตอร์ดังต่อไปนี้

เนื่องจากฉันมีตัวควบคุมการนำทางเป็นรูทฉันจึงยกตัวอย่างตัวควบคุมการนำทางเป็นตัวควบคุมมุมมองเริ่มต้น

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

let loginNav = loginSB.instantiateInitialViewcontroller() as! UINavigationController

Navigator.moveTo(loginNav, from: self)

สิ่งนี้จะลบกระดานเรื่องราว slpash ออกจากรูทของหน้าต่างแอพและแทนที่ด้วยกระดานเรื่องราวเข้าสู่ระบบ

จากกระดานเรื่องราวการเข้าสู่ระบบเมื่อผู้ใช้ลงชื่อเข้าใช้สำเร็จฉันบันทึกข้อมูลผู้ใช้เป็นค่าเริ่มต้นผู้ใช้และเริ่มต้น UserData ซิงเกิลตันเพื่อเข้าถึงรายละเอียดผู้ใช้ จากนั้นโหลดกระดานเรื่องราวของแถบแท็บโดยใช้วิธีการนำทาง

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

Navigator.moveTo(tabBarNav, from: self)

ตอนนี้ผู้ใช้ออกจากหน้าจอการตั้งค่าในแถบแท็บ ฉันล้างข้อมูลผู้ใช้ที่บันทึกไว้ทั้งหมดและไปที่หน้าจอเข้าสู่ระบบ

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

let loginNav = loginSB.instantiateInitialViewcontroller() as! UINavigationController

Navigator.moveTo(loginNav, from: self)
  • ผู้ใช้เข้าสู่ระบบและบังคับให้ฆ่าแอป

เมื่อผู้ใช้เปิดแอปหน้าจอ Splash จะถูกโหลด ฉันตรวจสอบว่าผู้ใช้เข้าสู่ระบบและเข้าถึงข้อมูลผู้ใช้จากค่าเริ่มต้นของผู้ใช้หรือไม่ จากนั้นเริ่มต้น UserData Singleton และแสดงแถบแท็บแทนหน้าจอเข้าสู่ระบบ


-1

ขอบคุณวิธีแก้ปัญหาของ bhavya มีสองคำตอบเกี่ยวกับความรวดเร็ว แต่สิ่งเหล่านั้นยังไม่สมบูรณ์ ฉันได้ทำเช่นนั้นใน swift3.Below เป็นรหัสหลัก

ใน 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
}

ใน 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")
}

ในฟังก์ชั่น logOutAction

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

สวัสดีอีไล คำถามที่คุณตอบแล้วมีคำตอบที่ดีจริงๆสองสามข้อ เมื่อคุณตัดสินใจที่จะตอบคำถามดังกล่าวโปรดอธิบายว่าทำไมคำตอบของคุณดีกว่าคำตอบที่ดีที่โพสต์ไปแล้ว
Noel Widmer

สวัสดี Noel ฉันสังเกตเห็นคำตอบอื่น ๆ อย่างรวดเร็ว แต่ฉันคิดว่าคำตอบนั้นไม่เหมือนเดิม ดังนั้นฉันจึงส่งคำตอบเกี่ยวกับรุ่น swift3 มันจะช่วยให้โปรแกรมเมอร์ swift ใหม่ขอขอบคุณ! @Noel Widmer
WangYang

คุณสามารถเพิ่มคำอธิบายนั้นไว้ที่ด้านบนของโพสต์ได้หรือไม่ ด้วยวิธีนี้ทุกคนสามารถเห็นประโยชน์ของคำตอบของคุณได้ในทันที มีช่วงเวลาที่ดีใน SO! :)
Noel Widmer

1
รถถังสำหรับคำแนะนำของคุณฉันเพิ่มคำอธิบายแล้วขอบคุณอีกครั้ง @ Noel Widmer
WangYang

โซลูชันที่คลุมเครือซึ่งไม่เน้นการใช้คำหลัก 'ทั่วไป'
Samarey

-3

ป้อนคำอธิบายรูปภาพที่นี่

ในแอป 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;

}

ดู controller.m ในมุมมองไม่โหลด

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

}

ในการดำเนินการปุ่มออกจากระบบ

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

ทำไมมีความจำเป็นต้องเพิ่มฟังก์ชั่นบางอย่างลงในไฟล์ ViewController.m
Eesha

@Eesha เขาเพิ่มรายการปุ่ม TabBar "ออกจากระบบ" เพื่อ TabBar ฉันคิดว่าภาพหายไปอย่างอื่นที่คุณสามารถเห็นมัน
helloWorld

รหัสเข้าสู่ระบบของร้านค้าNSUserDefaultsนั้นไม่ปลอดภัยอย่างมากสำหรับข้อมูลประเภทนั้น!
skywinder
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.