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:
- создайте свойство в AppDelegate.h таким образом, он будет доступен из классов, использующих его
@property (nonatomic, strong) myViewControllerClass*vC;
- на
viewDidLoad
внутри myViewControllerClass.m я получаю доступ к общему экземпляру AppDelegate и передаю свойство с помощью self:[AppDelegate sharedInstance].vC = self;
мне пришлось использовать это решение в сложной раскадровке и все же не могу смириться с тем, что я не могу найти простой способ доступа все (или по крайней мере те, что мне нужно) объекты в раскадровке просто путем адресации их идентификаторов.
еще одна вещь, чтобы проверить, если viewcontroller, который бросает ошибку, имеет storyboardIdentifier, вы можете проверить файл раскадровки xib.
идентификатор отсутствовал в моем случае, ошибка остановилась, когда я добавил его