Раскадровка - см. ViewController в AppDelegate

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

то есть. в AppDelegate я могу добраться до базового ViewController, такого как

(MyViewController*) self.window.rootViewController

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

Ответ 1

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

enter image description here

EDITED добавить пример кода:

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

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];

Ответ 2

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

  • Выберите 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;

Ответ 3

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

Итак, скажем, ваш rootViewController - это UINavigationController, а затем вы хотите отправить что-то в свой контроллер верхнего уровня, вы сделали бы это в AppDelegate didFinishLaunchingWithOptions:

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

В Swift, если бы было очень похоже:

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: и, возможно, его root, если он является контейнером, например, UINavigationController. То, что вы хотите избежать, - это создавать экземпляры контроллеров представлений, которые уже были созданы с помощью раскадровки. Это проблема, которую я вижу много. Короче говоря, я не согласен с принятым ответом. Это неверно, если плакаты не позволяют удалить загрузку раскадровки из info.plist, поскольку в противном случае вы загрузите 2 раскадровки, что не имеет смысла. Вероятно, это не утечка памяти, потому что система инициализировала корневую сцену и назначила ее окну, но затем вы пришли и снова создали его и снова назначили. Ваше приложение отключено до очень плохого начала!

Ответ 4

    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Tutorial" bundle:nil];
    self.window.rootViewController = [storyboard instantiateInitialViewController];