Условно начать в разных местах раскадровки из 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
}
Я знаю о методе performSegueWithIdentifier: но это метод-это метод экземпляра UIViewController, поэтому он не вызывается из AppDelegate. Как это сделать с помощью существующей раскадровки ??
EDIT:
начальный контроллер вида раскадровки теперь является навигационным контроллером, который ни к чему не подключен. Я использовал 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;
}
предложения/улучшения приветствуются!
10 ответов:
Я предполагаю, что ваша раскадровка установлена как "главная раскадровка" (ключ
UIMainStoryboardFile
в вашей информации.файл plist). В этом случае UIKit загрузит раскадровку и установит свой начальный контроллер вида в качестве корневого контроллера вида вашего окна перед отправкойapplication:didFinishLaunchingWithOptions:
к вашему AppDelegate.Я также предполагаю, что начальный контроллер вида в вашей раскадровке-это навигационный контроллер, на который вы хотите нажать свой основной контроллер или контроллер входа в систему.
вы можете попросить свое окно для его корня просмотр контроллера, и отправить
performSegueWithIdentifier:sender:
сообщение:NSString *segueId = success ? @"pushMain" : @"pushLogin"; [self.window.rootViewController performSegueWithIdentifier:segueId sender:self];
Я удивлен некоторыми из решений, предлагаемых здесь.
на самом деле нет необходимости в фиктивных навигационных контроллерах в вашей раскадровке, скрывающих виды и запускающих сегменты на 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; }
Если раскадровку и настроен в plist приложения, контроллер окна и корневого представления уже будет настроен к моменту вызова приложения: didFinishLaunching:, и makeKeyAndVisible будет вызван в окне для вас.
в таком случае, это даже проще:
- (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; }
если точка входа вашего раскадровки не является
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
заменить://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];
в вашем 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 между этим пусковым контроллером и тем, который вы хотите фактически запустить (тот, который после segue).оберните этот код в
if
условно, если вы не всегда хотите, чтобы это произошло.
учитывая, что вы уже используете раскадровку, вы можете использовать это, чтобы представить пользователю MyViewController, пользовательский контроллер (кипящий followben это немного).
на AppDelegate.м:
-(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, ссылается на идентификатор раскадровки, который можно установить в interface builder:
просто оберните это в логику по мере необходимости.
Если вы начинаете с UINavigationController, хотя этот подход не даст вам элементы управления навигацией.
чтобы "перейти вперед" от начальной точки навигационного контроллера, настроенного через interface builder, используйте этот подход:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UINavigationController *navigation = (UINavigationController *) self.window.rootViewController; [navigation.visibleViewController performSegueWithIdentifier:@"my-named-segue" sender:nil]; return YES; }
Почему бы не иметь экран входа в систему, который появляется первым, проверить, если пользователь уже вошел в систему и нажать на следующий экран сразу? Все в ViewDidLoad.
быстрая реализация же :
Если вы используете
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) }
Это решение, которое работало n iOS7. Чтобы ускорить начальную загрузку и не делать ненужной загрузки, у меня есть полностью пустой UIViewcontroller под названием "DUMMY" в моем файле раскадровки. Тогда я могу использовать следующий код:
- (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; }
Я предлагаю создать новый MainViewController, который является контроллером корневого представления навигационного контроллера. Для этого просто удерживайте control, затем перетащите соединение между навигационным контроллером и MainViewController, выберите "Relationship - Root View Controller" из приглашения.
В MainViewController:
- (void)viewDidLoad { [super viewDidLoad]; if (isLoggedIn) { [self performSegueWithIdentifier:@"HomeSegue" sender:nil]; } else { [self performSegueWithIdentifier:@"LoginSegue" sender:nil]; } }
Не забудьте создать сегменты между MainViewController с контроллерами Home и Login view. Надеюсь, это поможет. :)
попробовав много разных методов, я смог решить эту проблему с помощью этого:
-(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; }