Раскадровка - обратитесь к ViewController в AppDelegate

122

рассмотрим следующий сценарий: у меня есть приложение на основе раскадровки. Я добавляю объект ViewController в раскадровку, добавляю файлы классов для этого ViewController в проект и указываю имя нового класса в инспекторе идентичности IB. Как мне теперь программно обратиться к этому ViewController из AppDelegate? Я создал переменную с соответствующим классом и превратил ее в свойство IBOutlet, но я не вижу возможности ссылаться на новый ViewController в коде - любая попытка перетаскивания соединения с помощью Ctrl не работает ,

т.е. внутри AppDelegate я могу добраться до базового ViewController следующим образом

(MyViewController*) self.window.rootViewController

но как насчет любого другого ViewController, содержащегося в раскадровке?

Маттиас Д.
источник
Отметьте этот ответ . Это быстро, но языки похожи.
Borzh

Ответы:

165

Посмотрите документацию для -[UIStoryboard instantiateViewControllerWithIdentifier:]. Это позволяет вам создать экземпляр контроллера представления из вашей раскадровки, используя идентификатор, который вы установили в инспекторе атрибутов IB:

введите описание изображения здесь

ИЗМЕНИТЬ, чтобы добавить пример кода:

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                                         bundle: nil];

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];
Робин Саммерхилл
источник
Привет, Робин, спасибо за это! Я просмотрел этот документ, но перепутал слова instantiate и initialise ... это приводит нас туда (после выполнения вашей инструкции :) (черт возьми, отсутствие форматирования кода в ответах ...) UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName: @ Пакет "MainStoryboard": ноль]; MyViewController * thisController = (MyViewController *) [mainStoryboard instantiateViewControllerWithIdentifier: @ "myvc"];
Matthias D
Я добавил ваш пример кода в ответ с форматированием для всех, кто на это смотрит.
Робин Саммерхилл
24
если вы делаете универсальное приложение, обязательно используйте MainStoryboard_iPhone / MainStoryboard_iPad, иначе вы получите сбой.
roocell
16
Из делегата вы можете получить доступ к экземпляру раскадровки, загруженному вашим info.plist следующим образом: [[[self window] rootViewController] storyboard] Согласно документам, это вернет «раскадровку, из которой произошел контроллер представления». (или ноль, если это не из раскадровки). Из этого UIStoryboard * вы можете использовать вызовы экземпляра, упомянутые @RobinSummerhill. Обратите внимание, что раскадровки создают новые экземпляры ваших viewControllers ( сцен ) по мере необходимости и не используют повторно те, которые были просмотрены ранее.
Tad Bumcrot 08
6
Я полагаю, что ОП хочет знать, КАК ДОБРАТЬСЯ НА ТЕКУЩИЙ ВИДЕО. Не как загрузить. В точности, как он объясняет, раньше вы могли произносить этот self.window.rootViewController, а теперь больше не можете.
Fattie
41

Если вы используете XCode5, вы должны сделать это по-другому.

  • Выберите свой UIViewControllerвUIStoryboard
  • Перейдите Identity Inspectorна правую верхнюю панель
  • Установите Use Storyboard IDфлажок
  • Напишите уникальный идентификатор в Storyboard IDполе

Затем напишите свой код.

// Override point for customization after application launch.

if (<your implementation>) {
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" 
                                                             bundle: nil];
    YourViewController *yourController = (YourViewController *)[mainStoryboard 
      instantiateViewControllerWithIdentifier:@"YourViewControllerID"];
    self.window.rootViewController = yourController;
}

return YES;
Фарук Топтас
источник
4
Насколько я знаю и смог попробовать, это обновленный ответ.
gnclmorais
Имя раскадровки - это имя файла без расширения, поэтому это также может быть «Main_iPhone» или «Main_iPad», если вы настроили свой проект таким образом.
Брайан Уайт,
а затем как нам вернуться к исходному rootViewController после входа в систему. По крайней мере, насколько мне известно об iOS 7 и Xcode 5.0.2 - изменение корневого контроллера представления будет немедленно и без анимации переключить иерархию представления. Команда UX убила кодеров за меньшие деньги.
lol
Как мне это сделать с помощью Swift?
Лео Дабус
8

Как правило, система должна обрабатывать создание экземпляра контроллера представления с помощью раскадровки. Что вы хотите, так это пройти иерархию viewController, захватив ссылку на, self.window.rootViewControllerа не на инициализацию контроллеров представления, которые уже должны быть правильно инициализированы, если вы правильно настроили раскадровку.

Итак, предположим, что вы rootViewControllerUINavigationController, а затем вы хотите отправить что-то в его контроллер верхнего вида, вы бы сделали это в своем AppDelegate следующим образом didFinishLaunchingWithOptions:

UINavigationController *nav = (UINavigationController *) self.window.rootViewController;
MyViewController *myVC = (MyViewController *)nav.topViewController;
myVC.data = self.data;

В Swift if будет очень похоже:

let nav = self.window.rootViewController as! UINavigationController;
let myVC = nav.topViewController as! MyViewController
myVc.data = self.data

Вам действительно не следует инициализировать контроллеры представления с использованием идентификаторов раскадровки от делегата приложения, если вы не хотите обойти обычный способ загрузки раскадровки и загрузить всю раскадровку самостоятельно. Если вам нужно инициализировать сцены из AppDelegate, вы, скорее всего, делаете что-то не так. Я имею в виду, что вы по какой-то причине хотите отправить данные в контроллер представления вниз по стеку, AppDelegate не должен попадать в стек контроллера представления для установки данных. Это не его дело. Это дело rootViewController. Позвольте rootViewController обрабатывать своих собственных потомков! Итак, если бы я обходил обычный процесс загрузки раскадровки системой, удаляя ссылки на нее в файле info.plist, я бы в лучшем случае создал экземпляр rootViewController, используяinstantiateViewControllerWithIdentifier:, и, возможно, его корень, если это контейнер, например UINavigationController. Чего вы хотите избежать, так это создания экземпляров контроллеров представления, которые уже были созданы раскадровкой. Я часто вижу эту проблему. Короче не согласен с принятым ответом. Это неверно, если плакаты не предназначены для удаления загрузки раскадровки из info.plist, поскольку в противном случае вы загрузите 2 раскадровки, что не имеет смысла. Вероятно, это не утечка памяти, потому что система инициализировала корневую сцену и назначила ее окну, но затем вы пришли, создали ее снова и назначили снова. Ваше приложение запущено очень плохо!

smileBot
источник
0
    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Tutorial" bundle:nil];
    self.window.rootViewController = [storyboard instantiateInitialViewController];
Офир Малачи
источник