2012-05-31 39 views
15

我剛剛開始使用iOS編程,到目前爲止,我在這裏找到的教程和答案對於向前邁進有很大的幫助。然而,這個特殊問題一直困擾着我整夜,我找不到一個「感覺正確」的答案。在應用程序啓動時從故事板中選擇替代第一個視圖控制器

我正在編寫一個連接到遠程服務的應用程序,用戶需要先登錄才能使用它。當他們開始使用應用程序時,他們的第一個視圖應該是登錄對話框;當他們之前通過身份驗證時,他們會立即看到概述頁面。

該項目使用故事板 - 我認爲這是一個很棒的功能 - 所以大多數選擇和加載根視圖控制器的代碼已經被處理。我以爲最好的地方加入我的邏輯是AppDelegateapplication:didFinishLaunchingWithOptions:方法:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: 
     (NSDictionary *)launchOptions 
{ 
    // select my root view controller here based on credentials present or not 
    return YES; 
} 

但是,這帶來了兩個問題:

  1. 這裏面具體的委託方法,根視圖控制器早已已根據故事板選定(並加載?)。我可以移動到加載過程中的較早位置來覆蓋第一個視圖控制器選擇,還是會不必要地使問題複雜化?

  2. 要覆蓋第一個視圖控制器,我需要對故事板的引用,但我找不到比使用UIStoryboardstoryboardWithName:bundle:構造函數更好的方法。這感覺不對,應用程序應該已經有了故事板的參考,但是我怎樣才能訪問它?

更新

我計算出我有第二個問題,因爲我發現我的答案在這裏:

UIStoryboard: What's the Correct Way to Get the Active Storyboard?

NSBundle *bundle = [NSBundle mainBundle]; 
NSString *sbFile = [bundle objectForInfoDictionaryKey:@"UIMainStoryboardFile"]; 
UIStoryboard *sb = [UIStoryboard storyboardWithName:sbFile bundle:bundle]; 

以上將創建一個新的故事董事會實例;獲取活動實例,它是一大堆簡單:

UIStoryboard *sb = [[self.window rootViewController] storyboard]; 

在故事板文件本身,你必須設置要加載,如視圖標識符LoginDialog。然後你實例化這樣的觀點:

LoginViewController *login = [sb instantiateViewControllerWithIdentifier:@"LoginDialog"]; 
[self.window setRootViewController:login]; 

在另一個視圖控制器,以下就足夠了:

UIStoryboard *sb = self.storyboard; 
LoginViewController *login = [sb instantiateViewControllerWithIdentifier:@"LoginDialog"]; 
[self presentViewController:login animated:NO completion:nil]; 

回答

13

你可以只重置窗口

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: 
     (NSDictionary *)launchOptions 
{ 
    if(your_condition) { 
     UIViewController *newRoot = [your implementation]; 
     self.window.rootViewController = newRoot; 
    } 
    return YES; 
} 

這是爲我工作的根視圖控制器,Xcode5.0.1

+5

'/ *對於故事板... */self.window.rootViewController =(YourViewController *)[[UIStoryboard storyboardWithName:@「Main」 bundle:nil] instantiateViewControllerWithIdentifier:@「YourViewControllerID」];' –

2

我剛用故事板&或許這不是確切的回答你的問題。但我會以某種方式向你建議我在我的項目中所做的事情,而不使用故事板。

didFinishLaunchingWithOptionsAuthenticationViewController是加載的第一個視圖。它要求登錄憑證。一旦輸入,它將進入項目使用的實際ViewControllers(即TabBar & all ..)。

添加到項目中的有趣功能是,當您輸入憑證時,我彈出一個UIAleretView,要求用戶選擇三個選項之一。

  1. 保存憑據沒有密碼
  2. 保存憑據密碼
  3. 不要保存憑據

路過這裏的代碼是什麼,但通過用戶輸入4位數編號。每當他想要'使用密碼保存憑證'時,我會在其完成引腳輸入時顯示默認鍵盤& popviewController的NumberPad instad的默認值pushViewController。如果用戶'以後不保存憑據'&在播放應用程序時想要轉到其他身份驗證選項,那麼我將TabBarController的最後一個選項卡添加爲'設置'選項卡,其中我允許用戶選擇其中一個身份驗證選項,彈出爲UIAlertView在登錄後啓動應用程序的開始。

不要忘記在keychain

保存憑據簡而言之,

  1. AuthenticationViewController->檢查登錄憑據存儲在鑰匙串

1.1。如果沒有存儲(即3.不保存憑據) - >然後顯示登錄頁面。

1.2。如果憑證保存在鑰匙串中 - >提取他們&看看它是否與密碼綁定。

1.2.1。如果密碼與密碼綁定(即保存密碼爲 的憑證) - >然後顯示密碼頁面。

1.2.2。如果沒有綁定(1.保存沒有密碼的憑證) - >然後顯示/載入您項目的TabBarController層次或其他東西。這裏實際上你的應用開始

+1

謝謝!我喜歡增加一個密碼;目前我只是在關鍵鏈上寫下賬戶詳情。當然,我可以讓身份驗證視圖根據是否可以找到存儲的憑據來執行視圖更改,但我寧願早些時候完成視圖更改。 –

+0

好的。當你使用storyboard成功完成這個任務時,我建議你將它作爲github或博客上的示例項目發佈。這將真正指導初學者。 –

+1

當然!發現問題的第二部分btw :) –

7

我有和你一樣的情景。我的應用程序使用UINavigationController作爲根視圖控制器。如果用戶已登錄,我想向他/她呈現NotLoggedInViewController,如果它已登錄,我想顯示LoggedInViewController

在故事板中,UINavigationController只能有一個孩子,所以您必須能夠以編程方式爲其分配另一個根視圖控制器。

我從創建自定義導航控制器類開始,我們將其命名爲MyNavigationController。在故事板中,我將此自定義類分配給導航控制器對象。

仍然在故事板中,我對兩個視圖控制器建模,並將其中一個連接到導航控制器對象。由於我需要能夠稍後從我的代碼訪問它們,因此我使用右側的XCode檢查器爲它們分配了一個標識符。這些標識符可以是任意字符串,但爲了簡單起見,我只是使用類名。

最後我再落實MyNavigationControllerviewDidLoad方法:

BOOL isLoggedIn = ...; 

- (void)viewDidLoad { 
    id rootController; 
    if (isLoggedIn) { 
    rootController = [self.storyboard instantiateViewControllerWithIdentifier:@"LoggedInViewController"]; 
    } else { 
    rootController = [self.storyboard instantiateViewControllerWithIdentifier:@"NotLoggedInViewController"]; 
    } 
    self.viewControllers = [NSArray arrayWithObjects:rootController, nil]; 
} 
+0

感謝您的答案;它證實了我發現自己關於如何獲得對活動故事板的引用並從中實例化視圖的答案:)我的決定正在嚮應用程序委託內部添加邏輯,主要是爲了集中處理密碼更改(遠程服務確實不支持會話和哈希密碼在每個請求發送)...仍在工作 –

-1

隨着主要故事板已經加載,這只是一個找到它的參考問題,以便我可以實例化另一個根視圖控制器:

UIStoryboard *mainStoryboard = self.window.rootViewController.storyboard; 

self.window.rootViewController = [mainStoryboard 
    instantiateViewControllerWithIdentifier:@"view-controller-id"]; 
+0

它會炸燬。 Segues會被打破,你會從UIKit得到一些警告,上帝知道,也許在iOS 9中會導致CRASH。 – Andy

+0

@Andy出於好奇,UIKit的警告是什麼? –

+0

「警告:嘗試在視圖不在窗口層次結構中的XXX上呈現XXX!」但是在清理狀態恢復緩存後,我發現它已經消失了。無論如何,這種方法可以打破故事板流程和狀態恢復流程。 – Andy

相關問題