2012-05-31 4 views
15

Я только что начал программировать на iOS, и до сих пор учебные пособия и ответы, которые я нашел здесь, были большой помощью для продвижения вперед. Тем не менее, эта конкретная проблема натирала меня всю ночь, и я не могу найти ответ, который «чувствует себя хорошо».Выбор альтернативного контроллера первого взгляда из панели рассказов при запуске приложения

Я пишу приложение, которое подключается к удаленной службе, и пользователям необходимо войти в систему, прежде чем они смогут его использовать. Когда они начинают использовать приложение, их первым представлением должен быть диалог входа в систему; когда они уже прошли проверку подлинности, они сразу же видят страницу обзора.

Проект использует доски объявлений, которые, как я считаю, являются отличной функцией, поэтому большую часть кода, который выбирает и загружает контроллер корневого представления, уже позаботился. Я думал, что лучшее место, чтобы добавить мою логика является application:didFinishLaunchingWithOptions: метода AppDelegate:

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

Но это воспитывается два вопроса:

  1. Внутри этого конкретного метода делегата, контроллер вида корня имеет уже был выбран (и загружен?) на основе доски объявлений. Могу ли я перейти на более раннее место в процессе загрузки, чтобы переопределить первый выбор контроллера просмотра, или это бы неудобно усложняло вопросы?

  2. Чтобы переопределить первый контроллер представления, мне нужна ссылка на панель рассказов, но я не мог найти лучшего способа, чем использовать конструктор storyboardWithName:bundle:UIStoryboard. Это неправильно, приложение должно уже иметь ссылку на доску объявлений, но как я могу получить к ней доступ?

Update

Я разработал второй вопрос у меня был, как я нашел мой ответ здесь:

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 & все ..), используемые проектом.

Интересная функция, добавленная в проект, когда вы вводите учетные данные, я вытащил UIAleretView, который просит пользователя выбрать один из трех вариантов.

  1. Сохранить учетные данные без пароля
  2. сохранить учетные данные с паролем
  3. Dont сохранить учетные данные

Здесь проходят код ничего, кроме 4-х символьный числа, введенного пользователем. Всякий раз, когда он хочет «Сохранить учетные данные с кодом доступа», I pushViewController, который показывает инсталляцию NumPad стандартной клавиатуры & popviewController, когда он заканчивает ввод PIN-кода. Если пользователь «Не сохранять учетные данные» & позже во время воспроизведения приложения хочет перейти на другие параметры проверки подлинности, я добавил последнюю вкладку TabBarController в качестве вкладки «Настройки», внутри которой я разрешаю пользователю выбирать один из параметров проверки подлинности, который вызывается как UIAlertView в начале запуска приложения после входа в систему.

Не забудьте, чтобы сохранить учетные данные в keychain

В двух словах,

  1. AuthenticationViewController-> проверить, если учетные данные сохраняются в связке ключей

1.1. Если не сохранено (т. Е. 3. Не сохранять учетные данные) -> затем отобразить страницу входа.

1.2. Если учетные данные сохраняются в keychain-> извлечения их &, посмотрите, связана ли она с кодом доступа.

1.2.1. Если он связан с кодом доступа (то есть 2. Сохраните учетные данные с кодом доступа ) -> затем отобразите страницу с паролем.

1.2.2. Если он не привязан (1. Сохраните учетные данные без кода доступа) -> затем покажите/загрузите иерархию проекта TabBarController или другое. здесь на самом деле ваше приложение запускается.

+1

Спасибо! Мне нравится добавление кода прохода; в настоящее время я просто пишу детали аккаунта в цепочке ключей. Конечно, я мог бы иметь представление проверки подлинности, выполняющее изменение вида, исходя из того, могу ли я найти сохраненные учетные данные, но я предпочел бы, чтобы это было сделано раньше. –

+0

Хорошо. Когда вам удастся сделать это с помощью раскадровки, я бы предложил вам опубликовать это как пример проекта где-то в github или вашем блоге. Это действительно поможет новичкам. –

+1

Конечно! Выяснил вторую часть вопроса btw :) –

7

У меня такой же сценарий, как ваш. В моем приложении используется контроллер UINavigationController. Если пользователь вошел в систему, я хочу представить его NotLoggedInViewController, а если он вошел в систему, я хочу показать LoggedInViewController.

В раскадровке UINavigationController может иметь только один ребенок, поэтому вы должны иметь возможность программно назначать ему другой контроллер корневого представления.

Начну с создания пользовательского класса контроллера навигации, назовем его MyNavigationController. В раскадровке я назначаю этот настраиваемый класс объекту навигационного контроллера.

Все еще в раскадровке я затем моделирую оба контроллера вида и подключаю один из них к объекту контроллера навигации. Поскольку я должен иметь возможность получить к ним доступ из моего кода позже, я назначаю каждому из них идентификатор с помощью инспектора XCode справа. Эти идентификаторы могут быть произвольными строками, но для простых вещей я просто использую имена классов.

Наконец, я затем реализовать метод viewDidLoad на MyNavigationController класса:

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

Смежные вопросы