Розгорнення - див. ViewController в AppDelegate


122

врахуйте наступний сценарій: У мене є додаток на основі розкадровки. Я додаю об’єкт ViewController на табло, додаю файли класів для цього ViewController в проект і вказую ім'я нового класу в інспектора ідентичності IB. Тепер, як я буду програмно посилатися на цей ViewController програмно? Я створив змінну з відповідним класом і перетворив її у властивість IBOutlet, але я не бачу способу звернутися до нового ViewController у коді - будь-яка спроба ctrl-перетягування з'єднання не працює .

тобто в межах AppDelegate я можу потрапити на базовий ViewController, як це

(MyViewController*) self.window.rootViewController

але як щодо будь-якого іншого ViewController, що міститься в раскадровці?


Перевірте цю відповідь . Це швидко, але мови схожі.
Борж

Відповіді:


165

Погляньте на документацію для -[UIStoryboard instantiateViewControllerWithIdentifier:]. Це дозволяє створити контролер подання даних із вашої розкадровки за допомогою ідентифікатора, встановленого в Інспекторі атрибутів IB:

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

РЕДАКТИВО, щоб додати приклад коду:

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

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

Привіт Робін, дякую за це! Я переглянув цей документ, але змішав слова instantiate та ініціалізація ... це потрапляє нас туди (після виконання вашої інструкції :) (чорт про відсутність форматування коду у відповідях ...) UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName: @ Пакет "MainStoryboard": нуль]; MyViewController * thisController = (MyViewController *) [mainStoryboard instantiateViewControllerWithIdentifier: @ "myvc"];
Маттіас Д

Я додав ваш приклад код у відповідь із форматуванням для тих, хто на це дивиться.
Робін Саммерхілл

24
якщо ви робите універсальний додаток, не забудьте використовувати MainStoryboard_iPhone / MainStoryboard_iPad, інакше ви отримаєте збій.
roocell

16
Зсередини делегата ви можете отримати доступ до екземпляра розкадровки, завантаженого вашим інформаційним списком, таким чином: [[[self window] rootViewController] storyboard] Згідно з документами, це поверне "табло, з якого виник контролер перегляду". (або нуль, якщо він не прийшов із розкадровки). З цього UIStoryboard * ви можете використовувати екземплярні виклики, про які згадував @RobinSummerhill. Зауважте, що дошки розгортки створюють нові екземпляри ваших представлених контролерів ( сцен ) у міру необхідності і не використовують повторно ті, що були переглянуті раніше.
Tad Bumcrot

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 було б дуже схоже:

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 дошки, що не має сенсу. Мабуть, це не витік пам'яті, оскільки система ініціалізувала кореневу сцену та призначила її у вікно, але потім ви прийшли та інстанціонували її знову та призначили її знову. Ваш додаток вимкнено досить погано!


0
    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Tutorial" bundle:nil];
    self.window.rootViewController = [storyboard instantiateInitialViewController];
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.