Instantiate View Controller из раскадровки против создания нового экземпляра

в чем функциональная разница между созданием экземпляра контроллера вида из раскадровки и созданием нового экземпляра? Например:

#import "SomeViewController.h"

...

SomeViewController *someViewController = [SomeViewController new];

и

#import "SomeViewController.h"

...

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];

SomeViewController *someViewController = [storyboard instantiateViewControllerWithIdentifier:@"SomeViewController"];

В любом случае, это someViewController фактически одно и то же?

7 ответов


основное различие заключается в том, как подвиды вашего UIViewController вам экземпляр.

во втором случае все виды, которые вы создаете в раскадровке, будут автоматически созданы для вас, а все розетки и действия будут настроены так, как вы указали в раскадровке.

в первом случае ничего этого не происходит; вы просто получаете необработанный объект. Вам нужно будет выделить и создать экземпляр всех ваших подвидов, выложить их с помощью ограничений или иным образом и подключить все розетки и действия самостоятельно. Apple рекомендует делая это, переопределяя loadView метод UIViewController.


во втором случае-представление-контроллер загружает вид из раскадровки и вы будете счастливы.

в первом случае это не будет. Если вы не предприняли другие шаги (например, переопределение loadView или viewDidLoad или создание xib с именем SomeViewController.xib), вы просто получите пустой белый вид и грустить.


Это не одно и то же. В раскадровке у вас, вероятно, есть некоторые элементы пользовательского интерфейса. Они могут иметь ограничения и настройки свойств через раскадровку. Когда вы создаете экземпляр viewcontroller через раскадровку, вы получаете все инструкции о том, где находятся эти подвиды и каковы их свойства. Если ты просто скажешь [SomeViewController new] вы не получаете все инструкции, которые раскадровка имеет для контроллера вида.

хороший тест будет добавить UIViewController на раскадровку и перетащите на нее красный вид. Создайте экземпляр с помощью обоих методов и посмотрите, в чем разница.


в Swift вы можете сделать то же самое с,

var someVC = self.storyboard?.instantiateViewControllerWithIdentifier("SomeViewController") as! SomeViewController

вам нужно будет дать идентификатор в раскадровке на SomeViewController и отметьте галочкой использовать раскадровку ID


simple swift 3 extension   
 fileprivate enum Storyboard : String {
        case main = "Main"
    }

    fileprivate extension UIStoryboard {
        static func loadFromMain(_ identifier: String) -> UIViewController {
            return load(from: .main, identifier: identifier)
        }

        static func load(from storyboard: Storyboard, identifier: String) -> UIViewController {
            let uiStoryboard = UIStoryboard(name: storyboard.rawValue, bundle: nil)
            return uiStoryboard.instantiateViewController(withIdentifier: identifier)
        }
    }

    // MARK: App View Controllers

    extension UIStoryboard {
        class func loadHomeViewController() ->  HomeViewController {
            return loadFromMain("HomeViewController") as! HomeViewController
        }
    }

в случае, если вы не хотите создавать экземпляр нового VC с помощью instantiateViewControllerWithIdentifier но доступ к экземпляру, созданному раскадровкой из AppDelegate:

  1. создайте свойство в AppDelegate.h таким образом, он будет доступен из классов, использующих его @property (nonatomic, strong) myViewControllerClass*vC;
  2. на viewDidLoad внутри myViewControllerClass.m я получаю доступ к общему экземпляру AppDelegate и передаю свойство с помощью self:[AppDelegate sharedInstance].vC = self;

мне пришлось использовать это решение в сложной раскадровке и все же не могу смириться с тем, что я не могу найти простой способ доступа все (или по крайней мере те, что мне нужно) объекты в раскадровке просто путем адресации их идентификаторов.


еще одна вещь, чтобы проверить, если viewcontroller, который бросает ошибку, имеет storyboardIdentifier, вы можете проверить файл раскадровки xib.

идентификатор отсутствовал в моем случае, ошибка остановилась, когда я добавил его