Как представить контроллер просмотра всплывающих окон / входа в систему с помощью раскадровки

Я видел этот вопрос в различных формах без четкого ответа. Я собираюсь спросить и ответить здесь. Моему приложению нужно выполнять работу при запуске … inits, несколько сетевых вызовов, логин и т. Д. Я не хочу, чтобы мой главный контроллер представления работал до тех пор, пока это не будет выполнено. Что хорошего для этого?

Требования:

  • iOS5 +, раскадровки, ARC.
  • основной вид vc не может появиться до тех пор, пока не будет выполнена работа по запуску.
  • хотите, чтобы выбор стилей перехода на главный vc выполнялся при запуске.
  • хотите сделать как можно больше макета в раскадровке.
  • код должен быть чистым, где-то очевидным.

2 Solutions collect form web for “Как представить контроллер просмотра всплывающих окон / входа в систему с помощью раскадровки”

EDIT, июль 2017 года. После первого написания я изменил свою практику на ту, где я запускаю задачи для своего собственного контроллера представления. В этом VC я проверяю условия запуска, при необходимости нажимаю «занятый» интерфейс и т. Д. На основании состояния при запуске я устанавливаю корень VC окна.

В дополнение к решению проблемы ОП этот подход имеет дополнительные преимущества, позволяющие лучше контролировать запуск UI и UI-переходов. Вот как это сделать:

В основной раскадровке добавьте новый VC, называемый LaunchViewController и сделайте его первоначальным vc. Дайте «реальный» первоначальный vc вашего приложения идентификатор типа «AppUI» (идентификаторы находятся на вкладке «Идентификация» в IB).

Идентифицируйте другие vcs, которые являются запусками основных потоков пользовательского интерфейса (например, регистрация / вход, учебное пособие и т. Д.) И дают эти описательные идентификаторы. (Некоторые предпочитают держать каждый поток в собственной раскадровке. Это хорошая практика, ИМО).

Еще одна приятная необязательная идея : также добавьте vc идентификатор запуска вашего приложения в качестве идентификатора (например, «LaunchVC»), чтобы вы могли его захватить и использовать его во время запуска. Это обеспечит беспрепятственный опыт для пользователя во время запуска и при выполнении задач запуска.

Вот как выглядит мой LaunchViewController

 @implementation LaunchViewController - (void)viewDidLoad { [super viewDidLoad]; // optional, but I really like this: // cover my view with my launch screen's view for a seamless start UIStoryboard *storyboard = [self.class storyboardWithKey:@"UILaunchStoryboardName"]; UINavigationController *vc = [storyboard instantiateViewControllerWithIdentifier:@"LaunchVC"]; [self.view addSubview:vc.view]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self hideBusyUI]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self showBusyUI]; // start your startup logic here: // let's say you need to do a network transaction... // [someNetworkCallingObject doSomeNetworkCallCompletion:^(id result, NSError *error) { if (/* some condition */) [self.class presentUI:@"AppUI"]; else if (/* some condition */) [self.class presentUI:@"LoginUI"]; // etc. }]; } #pragma mark - Busy UI // optional, but maybe you want a spinner or something while getting started - (void)showBusyUI { // in one app, I add a spinner on my launch storyboard vc // give it a tag, and give the logo image a tag, too // here in animation, I fade out the logo and fade in a spinner UIImageView *logo = (UIImageView *)[self.view viewWithTag:32]; UIActivityIndicatorView *aiv = (UIActivityIndicatorView *)[self.view viewWithTag:33]; [UIView animateWithDuration:0.5 animations:^{ logo.alpha = 0.0; aiv.alpha = 1.0; }]; } - (void)hideBusyUI { // an animation that reverses the showBusyUI } #pragma mark - Present UI + (void)presentUI:(NSString *)identifier { UIStoryboard *storyboard = [self storyboardWithKey:@"UIMainStoryboardFile"]; UINavigationController *vc = [storyboard instantiateViewControllerWithIdentifier:identifier]; UIWindow *window = [UIApplication sharedApplication].delegate.window; window.rootViewController = vc; // another bonus of this approach: any VC transition you like to // any of the app's main flows [UIView transitionWithView:window duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil]; } + (UIStoryboard *)storyboardWithKey:(NSString *)key { NSBundle *bundle = [NSBundle mainBundle]; NSString *storyboardName = [bundle objectForInfoDictionaryKey:key]; return [UIStoryboard storyboardWithName:storyboardName bundle:bundle]; } @end 

Первоначальный ответ ниже, хотя я предпочитаю свой нынешний подход

Давайте выражаем готовность приложения к запуску главного vc с булевым, что-то вроде:

 BOOL readyToRun = startupWorkIsDone && userIsLoggedIn; 
  1. Создайте AppStartupViewController и разместите его в раскадровке приложений.
  2. Не перетаскивайте его, и не делайте так, чтобы он смотрел vc, просто оставите его где-то плавающим.
  3. В инспекторе атрибутов vc в раскадровке установите его идентификатор как «AppStartupViewController».

В AppStartupViewController.m, когда условия readyToRun выполнены, он может отклонить себя:

 self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; // your choice here from UIModalTransitionStyle [self dismissViewControllerAnimated:YES completion:nil]; 

Теперь, когда приложение становится активным, оно может проверить готовность к запуску и представить AppStartupViewController, если это необходимо. В AppDelegate.h

 - (void)applicationDidBecomeActive:(UIApplication *)application { BOOL readyToRun = startupWorkIsDone && userIsLoggedIn; if (!readyToRun) { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil]; AppStartupViewController *startupVC = [storyboard instantiateViewControllerWithIdentifier:@"AppStartupViewController"]; [self.window.rootViewController presentViewController:startupVC animated:NO completion:nil]; // animate = NO because we don't want to see the mainVC's view } } 

В основном это ответ, но есть одна заминка. К сожалению, главный vc загружается (это нормально) и получает сообщение viewWillAppear: (не все), прежде чем будет представлен AppStartupViewController. Это означает, что в MainViewController.m необходимо добавить немного дополнительной логики запуска, например:

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if (readyToRun) { // the view will appear stuff i would have done unconditionally before } } 

Надеюсь, это полезно.

Другое решение при использовании навигационного контроллера.

  1. Ваш контроллер навигации является начальным контроллером представления, установите ваш основной контроллер в качестве корневого контроллера навигационного контроллера.

  2. Добавьте контроллер загрузки в раскадровку и свяжите его с именем segue стиля модального.

  3. В представлении вашего основного контроллераWillAppear запускает segue (только один раз для запуска приложения).

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if(_isFirstRun) { _isFirstRun = NO; [self performSegueWithIdentifier:@"segueLoading" sender:nil]; } } 

Это не сработает, если вы вызовите segue в viewDidLoad, вероятно, потому, что анимация контроллера навигации еще не завершена, и вы получите unbalanced calls to begin/end appearance transitions

  • hitTest возвращает неправильный UIView
  • UIFont Woes (некоторые пользовательские загрузки шрифтов, но другие - нет)
  • Вертикальный TabbarController (или TabBar)?
  • Имя очереди GCD для получения / метки
  • С программным обеспечением изменения влево-влево RTL
  • Запросить доступ к контактам устройства
  • Доступ к чтению заказа Проблема с использованием addChildViewController
  • Как поместить зеленую иконку Добавить в строке Вставить
  • Можно ли сортировать по подклассам в `NSFetchRequest` без добавления дополнительных атрибутов?
  • Целевое действие называется дважды
  • applicationWillResignActive и setBrightness не работают?
  • PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.