Условно начать в разных местах в раскадровке из AppDelegate
У меня есть раскадровка, настроенная с рабочим контроллером входа и основного вида, последний является контроллером представления, к которому пользователь перемещается, когда логин успешно завершен.
Моя цель состоит в том, чтобы показать главный контроллер представления сразу, если аутентификация (сохраненная в цепочке ключей) прошла успешно и покажет контроллер входа в систему, если аутентификация завершилась неудачно.
В принципе, я хочу сделать это в своем AppDelegate:
// url request & response work fine, assume success is a BOOL here
// that indicates whether login was successful or not
if (success) {
// 'push' main view controller
} else {
// 'push' login view controller
}
Я знаю о методе executeSegueWithIdentifier: но этот метод является методом экземпляра UIViewController, поэтому он не может быть вызван из AppDelegate.
Как мне это сделать, используя существующую раскадровку?
EDIT:
Контроллер начального представления Storyboard теперь является навигационным контроллером, который не подключен ни к чему. Я использовал setRootViewController: различение, потому что MainIdentifier является UITabBarController. Тогда вот как выглядят мои строки:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isLoggedIn = ...; // got from server response
NSString *segueId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:segueId];
if (isLoggedIn) {
[self.window setRootViewController:initViewController];
} else {
[(UINavigationController *)self.window.rootViewController pushViewController:initViewController animated:NO];
}
return YES;
}
Предложения/улучшения приветствуются!
Ответы
Ответ 1
Я предполагаю, что ваш раскадровка задан как "главная раскадровка" (клавиша UIMainStoryboardFile
в вашем Info.plist). В этом случае UIKit загрузит раскадровку и установит свой начальный контроллер представления в качестве вашего контроллера корневого окна Windows, прежде чем он отправит application:didFinishLaunchingWithOptions:
в AppDelegate.
Я также предполагаю, что контроллер начального представления в вашем раскадровке является навигационным контроллером, на который вы хотите нажать главный контроллер входа или входа.
Вы можете задать свое окно для своего контроллера корневого представления и отправить ему сообщение performSegueWithIdentifier:sender:
:
NSString *segueId = success ? @"pushMain" : @"pushLogin";
[self.window.rootViewController performSegueWithIdentifier:segueId sender:self];
Ответ 2
Я удивлен некоторыми предлагаемыми здесь решениями.
На самом деле нет необходимости в фиктивных навигационных контроллерах в вашем раскадровке, скрывая взгляды и снимая segues на viewDidAppear: или любые другие хаки.
Если у вас нет раскадровки, настроенной в вашем файле plist, вы должны сами создать окно и контроллер корневого представления:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isLoggedIn = ...; // from your server response
NSString *storyboardId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:storyboardId];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = initViewController;
[self.window makeKeyAndVisible];
return YES;
}
Если раскадровка настроена на панели приложений, контроллер окна и корневого представления уже будет настроен с помощью приложения времени: вызывается функция "Вызов по умолчанию: вызывается", а makeceyAndVisible вызывается в окне для вас.
В этом случае это еще проще:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isLoggedIn = ...; // from your server response
NSString *storyboardId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:storyboardId];
return YES;
}
Ответ 3
Если ваша точка входа в раскадровку не является UINavigationController
:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Your View Controller Identifiers defined in Interface Builder
NSString *firstViewControllerIdentifier = @"LoginViewController";
NSString *secondViewControllerIdentifier = @"MainMenuViewController";
//check if the key exists and its value
BOOL appHasLaunchedOnce = [[NSUserDefaults standardUserDefaults] boolForKey:@"appHasLaunchedOnce"];
//if the key doesn't exist or its value is NO
if (!appHasLaunchedOnce) {
//set its value to YES
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"appHasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
//check which view controller identifier should be used
NSString *viewControllerIdentifier = appHasLaunchedOnce ? secondViewControllerIdentifier : firstViewControllerIdentifier;
//IF THE STORYBOARD EXISTS IN YOUR INFO.PLIST FILE AND YOU USE A SINGLE STORYBOARD
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
//IF THE STORYBOARD DOESN'T EXIST IN YOUR INFO.PLIST FILE OR IF YOU USE MULTIPLE STORYBOARDS
//UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"YOUR_STORYBOARD_FILE_NAME" bundle:nil];
//instantiate the view controller
UIViewController *presentedViewController = [storyboard instantiateViewControllerWithIdentifier:viewControllerIdentifier];
//IF YOU DON'T USE A NAVIGATION CONTROLLER:
[self.window setRootViewController:presentedViewController];
return YES;
}
ЕСЛИ ваша точка входа в раскадровка есть UINavigationController
replace:
//IF YOU DON'T USE A NAVIGATION CONTROLLER:
[self.window setRootViewController:presentedViewController];
с:
//IF YOU USE A NAVIGATION CONTROLLER AS THE ENTRY POINT IN YOUR STORYBOARD:
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController pushViewController:presentedViewController animated:NO];
Ответ 4
В вашем методе AppDelegate application:didFinishLaunchingWithOptions
перед строкой return YES
добавьте:
UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
YourStartingViewController *yourStartingViewController = [[navigationController viewControllers] objectAtIndex:0];
[yourStartingViewController performSegueWithIdentifier:@"YourSegueIdentifier" sender:self];
Замените YourStartingViewController
именем вашего фактического класса контроллера первого вида (тот, который вы не хотите обязательно показывать) и YourSegueIdentifier
с фактическим именем сегмента между этим пусковым контроллером и тем, который вы хотите на самом деле начать (один после segue).
Оберните этот код в if
условный, если вы не всегда хотите, чтобы это произошло.
Ответ 5
Учитывая, что вы уже используете раскадровку, вы можете использовать ее, чтобы представить пользователю с помощью MyViewController, настраиваемого контроллера ( "Boiling down followben answer).
В AppDelegate.m:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MyCustomViewController *controller = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:@"MyCustomViewController"];
// now configure the controller with a model, etc.
self.window.rootViewController = controller;
return YES;
}
Строка, переданная в instantiateViewControllerWithIdentifier, относится к идентификатору раскадровки, который может быть установлен в конструкторе интерфейса:
![enter image description here]()
Просто оберните это логическим при необходимости.
Если вы начинаете с UINavigationController, этот подход не даст вам элементов управления навигацией.
Чтобы перепрыгнуть вперед с начальной точки навигационного контроллера, настроенного через построитель интерфейсов, используйте этот подход:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navigation = (UINavigationController *) self.window.rootViewController;
[navigation.visibleViewController performSegueWithIdentifier:@"my-named-segue" sender:nil];
return YES;
}
Ответ 6
Почему бы не отобразить первый экран входа в систему, проверьте, был ли пользователь уже зарегистрирован и сразу же нажмите следующий экран? Все в ViewDidLoad.
Ответ 7
Быстрая реализация:
Если вы используете UINavigationController
как точку входа в раскадровку
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var rootViewController = self.window!.rootViewController as! UINavigationController;
if(loginCondition == true){
let profileController = storyboard.instantiateViewControllerWithIdentifier("ProfileController") as? ProfileController
rootViewController.pushViewController(profileController!, animated: true)
}
else {
let loginController = storyboard.instantiateViewControllerWithIdentifier("LoginController") as? LoginController
rootViewController.pushViewController(loginController!, animated: true)
}
Ответ 8
Это решение, которое работает n iOS7.
Чтобы ускорить первоначальную загрузку и не выполнять ненужную загрузку, у меня есть полностью пустой UIViewcontroller под названием "DUMMY" в моем файле Storyboard. Затем я могу использовать следующий код:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
NSString* controllerId = @"Publications";
if (![NSUserDefaults.standardUserDefaults boolForKey:@"hasSeenIntroduction"])
{
controllerId = @"Introduction";
}
else if (![NSUserDefaults.standardUserDefaults boolForKey:@"hasDonePersonalizationOrLogin"])
{
controllerId = @"PersonalizeIntro";
}
if ([AppDelegate isLuc])
{
controllerId = @"LoginStart";
}
if ([AppDelegate isBart] || [AppDelegate isBartiPhone4])
{
controllerId = @"Publications";
}
UIViewController* controller = [storyboard instantiateViewControllerWithIdentifier:controllerId];
self.window.rootViewController = controller;
return YES;
}
Ответ 9
Я предлагаю создать новый MainViewController, который является контроллером Root View контроллера навигации. Для этого просто держите управление, затем перетащите соединение между контроллером навигации и MainViewController, выберите "Связь - контроллер корневого представления" из приглашения.
В MainViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
if (isLoggedIn) {
[self performSegueWithIdentifier:@"HomeSegue" sender:nil];
} else {
[self performSegueWithIdentifier:@"LoginSegue" sender:nil];
}
}
Не забудьте создать сегменты между MainViewController с контроллерами представления Home и Login.
Надеюсь это поможет.:)
Ответ 10
Попробовав много разных методов, я смог решить эту проблему следующим образом:
-(void)viewWillAppear:(BOOL)animated {
// Check if user is already logged in
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
if ([[prefs objectForKey:@"log"] intValue] == 1) {
self.view.hidden = YES;
}
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
// Check if user is already logged in
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
if ([[prefs objectForKey:@"log"] intValue] == 1) {
[self performSegueWithIdentifier:@"homeSeg3" sender:self];
}
}
-(void)viewDidUnload {
self.view.hidden = NO;
}