ストーリーボードを使ってiOSアプリを作成しています。ルートView ControllerはTab Bar Controllerです。私はログイン/ログアウトプロセスを作成しています、そしてそれは大抵うまく働いています、しかし私はいくつかの問題を持っています。これらすべてを設定するための最良の方法を知る必要があります。
次のことを達成したい。
これまでに行ったことは、ルートView ControllerをTab Bar Controllerに設定し、自分のLogin View Controllerにカスタムセグエを作成することです。私のTab Bar Controllerクラスの中で、それらがviewDidAppear
メソッドの中でログインしているかどうかをチェックし、そしてセグエを実行します:[self performSegueWithIdentifier:@"pushLogin" sender:self];
また、ログアウトアクションを実行する必要があるときの通知も設定しました。[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutAccount) name:@"logoutAccount" object:nil];
ログアウトしたら、キーチェーンから認証情報を消去し、[self setSelectedIndex:0]
を実行し、セグエを実行してログインView Controllerを再度表示します。
これはすべてうまくいきますが、私は思っています:このロジックはAppDelegateにあるべきですか?私には2つの問題があります。
viewWillAppear
に移動しようとしましたが、そのセグエはそれほど早くは機能しません。私はこれをやり直すことにオープンです。ログイン画面をルートView Controllerにするか、AppDelegateでナビゲーションコントローラを作成してすべてを処理することを検討しました。現時点で最良の方法が何であるかはわかりません。
これが私がすべてを達成するためにやったことです。あなたがこれに加えて考慮する必要がある唯一のものは(a)ログインプロセスと(b)あなたがあなたのアプリデータを保存しているところです(この場合、私はシングルトンを使いました)。
ご覧のとおり、ルートView Controllerはmyメインタブコントローラです。これは、ユーザーがログインした後、最初のタブに直接アプリを起動させたいためです。 (これにより、ログインビューに一時的に表示される「ちらつき」を回避できます。)
AppDelegate.m
このファイルでは、ユーザがすでにログインしているかどうかを確認します。ログインしていない場合は、ログインView Controllerをプッシュします。ログアウトプロセスも処理します。データを消去してログインビューを表示します。
- (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];
}
didFinishLaunchingWithOptions内のappDelegate.m
//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は、最初のView ControllerがサインインしたTabbarControllerであると想定しています。
if Auth.auth().currentUser == nil {
let rootController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "WelcomeNavigation")
self.window?.rootViewController = rootController
}
return true
サインアップView Controller:
@IBAction func actionSignup(_ sender: Any) {
let appDelegateTemp = UIApplication.shared.delegate as? AppDelegate
appDelegateTemp?.window?.rootViewController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateInitialViewController()
}
MyTabThreeViewController
//Remove user credentials
guard let appDel = UIApplication.shared.delegate as? AppDelegate else { return }
let rootController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "WelcomeNavigation")
appDel.window?.rootViewController = rootController
編集:ログアウトアクションを追加します。
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という名前のクラスを作成します。
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を作成し、ログインボタンがある最初のビューに接続します。ストーリーボード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 は、追加の支援を受けるためのサンプルプロジェクトです。
ビューコントローラの内部でAppDelegate
を使用し、rootViewController
を設定してもアニメーションが表示されないため、bhavyaの回答は嫌いでした。そしてTrevorの答えはiOS8上の点滅するView Controllerに関する問題を抱えている。
UPD 2015/07/18
ビューコントローラ内のAppDelegate:
View Controller内でAppDelegateの状態(プロパティ)を変更すると、カプセル化が解除されます。
すべてのiOSプロジェクトにおける非常に単純なオブジェクトの階層
AppDelegate(window
とrootViewController
を所有)
ViewController(view
を所有)
一番上のオブジェクトが一番下のオブジェクトを変更しても構いません。しかし、一番下のオブジェクトが一番上のオブジェクトを変更しても構いません(基本的なプログラミング/ OOPの原則:DIP(Dependency Inversion Principle:上位モジュールは下位モジュールに依存してはいけませんが抽象化に依存します))。 ).
いずれかのオブジェクトがこの階層内のいずれかのオブジェクトを変更する場合、遅かれ早かれコードに混乱が生じるでしょう。小規模なプロジェクトでは大丈夫かもしれませんが、少し混乱したプロジェクトでこの混乱を掘り下げるのは楽しいことではありません=]
UPD 2015/07/18
UINavigationController
(tl; dr: project をチェック)を使ってモーダルコントローラーのアニメーションを複製します。
私は自分のアプリのすべてのコントローラを表示するためにUINavigationController
を使っています。最初、私は普通のPush/popアニメーションでナビゲーションスタックにログインView Controllerを表示しました。私はそれを最小限の変更でモーダルに変更することにしました。
使い方:
初期のView Controller(またはself.window.rootViewController
)は、ProgressViewControllerをrootViewController
としたUINavigationControllerです。私はProgressViewControllerを見せています。なぜならDataModelはこの article のようにコアデータスタックに入るので初期化に時間がかかることがあるからです(私は本当にこのアプローチが好きです)。
AppDelegateは、ログインステータスの更新を取得する責任があります。
DataModelはユーザーのログイン/ログアウトを処理し、AppDelegateはKVOを介してuserLoggedIn
プロパティを監視しています。おそらくこれを行うための最善の方法ではありませんが、それは私のために働く。 (なぜKVOが悪いのか、 this または this article をチェックインすることができます。part) 。
ModalDismissAnimatorとModalPresentAnimatorは、デフォルトのプッシュアニメーションをカスタマイズするために使用されます。
アニメーターロジックの仕組み:
AppDelegateは、自身をself.window.rootViewController
(UINavigationController)のデリゲートとして設定します。
必要に応じて、AppDelegateはアニメーターの1つを-[AppDelegate navigationController:animationControllerForOperation:fromViewController:toViewController:]
に返します。
アニメーターは-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]];
}];
}
テストプロジェクトは here です。
これは将来の見物人のための私の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
}
}
ここから、私のプロトコル拡張はロジックを処理するか、あるいはログイン/ログアウトしているかどうかをユーザーが判断し、それに応じてウィンドウのrootViewControllerを変更します。
アプリデリゲートからこれを行うことはお勧めできません。 AppDelegateは、起動、一時停止、終了などに関連するアプリのライフサイクルを管理します。 viewDidAppear
の最初のView Controllerからこれを行うことをお勧めします。ログインビューコントローラからself.presentViewController
およびself.dismissViewController
を実行できます。初めて起動するかどうかを確認するには、bool
にNSUserDefaults
キーを格納します。
Xcode 7では、複数のstoryBoardsを持つことができます。ログインフローを別のストーリーボードに保存できればもっと良いでしょう。
これを使用して行うことができます ビューコントローラの選択>エディタ>ストーリーボードへのリファクタリング
そしてこれは、RootViewContollerとしてビューを設定するためのSwiftバージョンです。
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window!.rootViewController = newRootViewController
let rootViewController: UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("LoginViewController")
LoginViewController および TabBarController を作成したら、StoryboardIDを“ loginViewController ”および“ tabBarController ”として追加する必要があります。それぞれ。
それから、 Constant structを作成します。
struct Constants {
struct StoryboardID {
static let signInViewController = "SignInViewController"
static let mainTabBarController = "MainTabBarController"
}
struct kUserDefaults {
static let isSignIn = "isSignIn"
}
}
LoginViewController add IBAction :
@IBAction func tapSignInButton(_ sender: UIButton) {
UserDefaults.standard.set(true, forKey: Constants.kUserDefaults.isSignIn)
Switcher.updateRootViewController()
}
ProfileViewController add 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 classを作成します。
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
}
}
以上ですべてです!
これを使って最初の起動を確認します。
- (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で最初の起動を確認し、ログイン画面(login and register)でナビゲーションコントローラを作成します。これを現在のメインウィンドウの上に置きます。
[self.window makeKeyAndVisible];
if (firstLaunch == 1) {
UINavigationController *_login = [[UINavigationController alloc] initWithRootViewController:loginController];
[self.window.rootViewController presentViewController:_login animated:NO completion:nil];
}
これは通常のView Controllerの上にあるため、アプリの他の部分からは独立しています。もう必要ない場合は、View Controllerを閉じることができます。また、ユーザーが手動でボタンを押すと、ビューをこのように表示することもできます。
ところで:私はこのように私のユーザーからのログインデータを保存します:
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に自分のデータを必ず設定してください。
それでおしまい。
私はアプリで解決するために同様の問題があり、私は次の方法を使用しました。ナビゲーションを処理するために通知を使用しませんでした。
私はアプリ内に3つの絵コンテを持っています。
アプリの私の最初の絵コンテはSplashスクリーン絵コンテです。 View Controllerのナビゲーションを処理するためのログインおよびTab BarストーリーボードのルートとしてNavigation Controllerを持っています。
アプリのナビゲーションを処理するNavigatorクラスを作成しました。このクラスは次のようになります。
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)
}
}
}
}
考えられるシナリオを見てみましょう。
私はルートとしてNavigation Controllerを持っているので、最初のView ControllerとしてNavigation Controllerをインスタンス化します。
let loginSB = UIStoryboard(name: "splash", bundle: nil)
let loginNav = loginSB.instantiateInitialViewcontroller() as! UINavigationController
Navigator.moveTo(loginNav, from: self)
これにより、slpashストーリーボードがアプリウィンドウのルートから削除され、ログインストーリーボードに置き換えられます。
ログインストーリーボードから、ユーザーが正常にログインしたら、ユーザーデータをUser Defaultsに保存し、UserDataシングルトンを初期化してユーザーの詳細にアクセスします。次にTab barストーリーボードがナビゲーターメソッドを使ってロードされます。
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)
ユーザーがアプリを起動すると、スプラッシュスクリーンがロードされます。ユーザーがログインしているかどうかを確認し、ユーザーデフォルトからユーザーデータにアクセスします。次に、UserDataシングルトンを初期化し、ログイン画面の代わりにタブバーを表示します。
Bhavyaの解決に感謝します。Swiftについて2つの答えがありましたが、それらはそれほど損なわれていません。 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()
}
私はあなたと同じ状況にあり、データをきれいにするために私が見つけた解決策は、私のView Controllerがそれを情報を描画するのに頼っているすべてのCoreDataのものを削除することです。しかし、私はまだこのアプローチが非常に悪いと思っていました。ストーリーボードを使わずにコードを使用してView Controller間の遷移を管理することなく、よりエレガントな方法を実現できると思います。
私は このプロジェクト をGithubで見つけました。これはこれらすべてをコードによってのみ行い、理解するのは非常に簡単です。彼らはFacebookのようなサイドメニューを使い、彼らがしていることはユーザーがログインしているかいないかに応じてセンタービューコントローラを変更することです。ユーザがログアウトすると、appDelegate
はCoreDataからデータを削除し、メインView Controllerを再びログイン画面に設定します。