297 votes

Méthodes conseillées pour l’écran de connexion de Storyboard, compensation des données sur la déconnexion de manutention

Je suis en train de construire une application iOS à l'aide d'un Storyboard. La racine-vue-contrôleur est un Onglet de la Barre de Contrôleur. Je suis la création de la connexion/déconnexion du processus, et c'est surtout fonctionne très bien, mais j'ai quelques questions. J'ai besoin de savoir la MEILLEURE façon de mettre tout cela en place.

Je veux accomplir le suivant:

  1. Afficher un écran de connexion de la première fois que l'application est lancée. Lors de sa connexion, allez dans le premier onglet de la Barre d'Onglet Contrôleur.
  2. De tout temps, ils lancer l'application après cela, vérifiez s'ils sont connectés, et de passer directement à la première étiquette de la racine de la Barre d'Onglet Contrôleur.
  3. Quand ils manuellement cliquez sur un bouton de déconnexion, afficher l'écran de connexion, et d'effacer toutes les données de la vue des contrôleurs.

Ce que j'ai fait jusqu'à présent est de définir la vue de la racine de contrôleur de la Barre d'Onglet Contrôleur, et créé une coutume enchaîner à mon Login-vue-contrôleur. À l'intérieur de mon Onglet de la Barre de Contrôleur de classe, je vérifie s'ils sont enregistrés dans l'intérieur de l' viewDidAppear méthode, et d'effectuer la séquence: [self performSegueWithIdentifier:@"pushLogin" sender:self];

J'ai aussi l'installation d'une notification lors de la déconnexion de l'action à effectuer: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutAccount) name:@"logoutAccount" object:nil];

Lors de la déconnexion, je effacer les informations d'identification du Trousseau, exécutez [self setSelectedIndex:0] et d'effectuer la séquence pour afficher le nom de connexion-vue-contrôleur de nouveau.

Tout cela fonctionne bien, mais je me demandais: si cette logique d'être dans l'AppDelegate? J'ai également deux questions:

  • La première fois qu'ils le lancement de l'application, la Barre d'onglets de contrôle affiche brièvement avant la séquence est exécutée. J'ai essayé de déplacer le code d' viewWillAppear , mais la séquence ne sera pas le travail que les premiers.
  • Quand ils déconnexion, toutes les données sont toujours à l'intérieur de tous les contrôleurs de vue. Si ils se connecter à un nouveau compte, l'ancien compte de données est toujours affiché jusqu'à ce qu'ils actualiser. J'ai besoin d'un moyen de l'effacer facilement sur déconnexion.

Je suis ouvert à retravailler. J'ai réfléchi à l'écran de connexion de la vue racine contrôleur, ou la création d'une manette de navigation dans l'AppDelegate s'occuper de tout... je ne suis pas sûr de ce que la meilleure méthode est à ce point.

313voto

bhavya kothari Points 2876

Your storyboard should look like this

Dans votre appDelegate.m à l’intérieur de votre didFinishLaunchingWithOptions

Dans le fichier SignUpViewController.m

Dans le fichier MyTabThreeViewController.m

97voto

Trevor Gehman Points 474

Voici ce que j'ai fait pour tout faire. La seule chose que vous devez considérer en plus c'est (a) le processus de connexion et (b) l'endroit où vous stockez vos données d'application (dans ce cas, j'ai utilisé un singleton).

Storyboard showing login view controller and main tab controller

Comme vous pouvez le voir, la vue racine contrôleur est mon Onglet Principal Contrôleur. J'ai fait cela car une fois que l'utilisateur s'est connecté, je veux de l'application à lancer directement sur le premier onglet. (Ce qui évite toute "flicker" où la connexion view affiche temporairement.)

AppDelegate.m

Dans ce fichier, je vérifie si l'utilisateur est déjà connecté. Si pas, je pousse la connexion view controller. J'ai également gérer le processus de fermeture de session, où j'ai effacer les données et afficher le nom de connexion 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

Ici, si la connexion est réussie, j'ai simplement rejeter le point de vue et envoyer une notification.

-(void) loginWasSuccessful
{

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

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

}

20voto

dimimpou Points 1276

EDIT: Ajout de déconnexion de l'action.

enter image description here

1. Préparez d'abord le délégué d'application fichier

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. Créer une classe d'Utilisateur nommé.

De l'utilisateur.h

#import <Foundation/Foundation.h>

@interface User : NSObject

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

@end

De l'utilisateur.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. Créer un nouveau contrôleur RootViewController et est reliée à la première vision, où le bouton de connexion en direct. Ajouter également un 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. Créer un nouveau contrôleur LoginViewController et connecté avec le login vue.

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. À la fin, ajouter un nouveau contrôleur ProfileViewController et connecté avec la vue de profil dans le 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

Ici est un exemple de projet pour de l'aide supplémentaire.

3voto

Thorsten Points 1408

Je l'utilise pour vérifier pour le premier lancement:

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

(si l'utilisateur supprime l'application et ré-installe, il peut être considéré comme un premier lancement)

Dans l'AppDelegate-je vérifier d'abord lancer et de créer une barre de navigation-contrôleur avec les écrans de connexion (login et register), que j'ai mis sur le haut de la fenêtre principale:

[self.window makeKeyAndVisible];

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

Comme c'est sur la partie supérieure de la normale-vue-contrôleur, il est indépendant du reste de votre application et vous pouvez ignorer le point de vue du contrôleur, si vous en avez le plus besoin. Et vous pouvez aussi présenter le point de vue de cette façon, si l'utilisateur appuie sur un bouton manuellement.

BTW: j'ai enregistrer les données de connexion de mes utilisateurs comme ceci:

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

Pour la déconnexion: je suis passé loin de CoreData (trop lent) et l'utilisation NSArrays et NSDictionaries pour gérer mes données maintenant. Déconnexion juste de le vider ces tableaux et les dictionnaires. En Plus je assurez-vous de mettre mes données en viewWillAppear.

C'est tout.

0voto

amb Points 1719

Je suis dans la même situation que vous et la solution que j'ai trouvé pour le nettoyage des données est la suppression de tous les CoreData trucs que mon point de vue, les contrôleurs de compter sur de le dessiner l'info. Mais j'ai toujours trouvé cette approche très mauvais, je pense que d'une façon plus élégante de le faire peut être accompli sans story-boards et en utilisant uniquement du code pour gérer les transitions entre les contrôleurs de vue.

J'ai trouvé ce projet sur Github qui fait tout ce genre de choses que par le code et c'est assez facile à comprendre. Ils utilisent Facebook comme le menu de gauche et ce qu'ils ont à faire est de changer le centre-vue-contrôleur en fonction de si l'utilisateur est connecté ou non. Lorsque l'utilisateur se déconnecte l' appDelegate supprime les données de CoreData et définit la vue principale du contrôleur de l'écran de connexion à nouveau.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X