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


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

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

(MyViewController*) self.window.rootViewController

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

3 119

3 ответа:

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

enter image description here

отредактировано, чтобы добавить пример кода:

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

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

если вы используете 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;

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