Quelle est la différence fonctionnelle entre l'instanciation d'un contrôleur de vue à partir du storyboard et la création d'une nouvelle instance de celui-ci? Par exemple:
#import "SomeViewController.h"
...
SomeViewController *someViewController = [SomeViewController new];
versus
#import "SomeViewController.h"
...
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
SomeViewController *someViewController = [storyboard instantiateViewControllerWithIdentifier:@"SomeViewController"];
Dans les deux cas, someViewController
est-il effectivement la même chose?
La principale différence réside dans la façon dont les sous-vues de votre UIViewController
sont instanciées.
Dans le second cas, toutes les vues que vous créez dans votre storyboard seront automatiquement instanciées pour vous, et toutes les sorties et actions seront configurées comme vous l'avez spécifié dans le storyboard.
Dans le premier cas, rien de tout cela ne se produit; vous obtenez juste l'objet brut. Vous devrez allouer et instancier toutes vos sous-vues, les disposer en utilisant des contraintes ou autrement, et connecter vous-même tous les points de vente et actions. Apple recommande de faire cela en remplaçant la méthode loadView
de UIViewController
.
Dans le second cas, le contrôleur de vue chargera sa vue depuis le storyboard et vous serez content.
Dans le premier cas, ce ne sera pas le cas. À moins que vous n'ayez pris d'autres mesures (comme remplacer loadView
ou viewDidLoad
ou créer un xib nommé SomeViewController.xib
), vous aurez juste une vue blanche vide et serez triste.
Dans Swift vous pouvez faire de même avec,
var someVC = self.storyboard?.instantiateViewControllerWithIdentifier("SomeViewController") as! SomeViewController
Vous devrez donner l'identifiant dans le Storyboard au SomeViewController et cocher la coche pour Utiliser l'ID du Storyboard
Ce n'est pas la même chose. Dans le storyboard, vous disposez probablement de certains éléments d'interface utilisateur. Ils peuvent avoir des contraintes et des propriétés configurées via le storyboard. Lorsque vous instanciez le viewcontroller via le storyboard, vous obtenez toutes les instructions pour savoir où se trouvent ces sous-vues et quelles sont leurs propriétés. Si vous dites simplement [SomeViewController new]
vous n'obtenez pas toutes les instructions du storyboard pour le contrôleur de vue.
Un bon test consistera à ajouter un UIViewController à un storyboard et à y faire glisser une vue rouge. Instanciez-le en utilisant les deux méthodes et voyez quelles sont les différences.
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
}
}
Dans le cas où vous ne souhaitez pas instancier un nouveau VC en utilisant instantiateViewControllerWithIdentifier
mais en accédant à l'instance créée par le storyboard depuis AppDelegate:
@property (nonatomic, strong) myViewControllerClass*vC;
viewDidLoad
à l'intérieur de myViewControllerClass.m j'accède à l'instance partagée d'AppDelegate et alimente la propriété avec self: [AppDelegate sharedInstance].vC = self;
J'ai dû utiliser cette solution dans un storyboard complexe et je n'arrive toujours pas à surmonter le fait que je ne trouve pas un moyen facile d'accéder tous (ou au moins ceux dont j'ai besoin) objets dans le storyboard simplement en adresser leurs identifiants.
une autre chose à vérifier est si le viewcontroller qui lance l'erreur a un storyboardIdentifier, vous pouvez vérifier le fichier xib du storyboard.
l'identifiant manquait dans mon cas, l'erreur s'est arrêtée quand je l'ai ajouté