Instancier et présenter un viewController dans Swift

300

Problème

J'ai commencé à jeter un oeil du nouveau Swiftsur Xcode 6, et j'ai essayé quelques projets de démonstration et des tutoriels. Maintenant, je suis coincé à:

Instanciation puis présentation d'un à viewControllerpartir d'un storyboard spécifique

Solution Objective-C

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"myStoryboardName" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"myVCID"];
[self presentViewController:vc animated:YES completion:nil];

Comment y parvenir sur Swift?

E-Riddie
la source

Réponses:

648

Cette réponse a été révisée pour la dernière fois pour Swift 5.2 et iOS 13.4 SDK.


Tout est une question de nouvelle syntaxe et d'API légèrement révisées. La fonctionnalité sous-jacente d'UIKit n'a pas changé. Cela est vrai pour la grande majorité des frameworks SDK iOS.

let storyboard = UIStoryboard(name: "myStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "myVCID")
self.present(vc, animated: true)

Si vous rencontrez des problèmes init(coder:), veuillez vous référer à la réponse d' EridB .

akashivskyy
la source
3
Vous pouvez même omettre le ;! ;) Pourriez-vous élaborer sur le sujet as UIViewController? Pourquoi est-ce nécessaire?
Sebastian Wramba
5
asLe mot clé est utilisé pour la conversion de type. C'est la même chose que (UIViewController *)anObjectdans l'objectif c
Garoal
1
Oui, je sais que je peux les omettre, mais cela fait partie du long habbit. : D En tant que instantiateViewControllerWithIdentifierretours AnyObject( idéquivalent dans Swift) et je déclare vcque UIViewController, je dois transtyper AnyObjecten UIViewController.
akashivskyy
Salut les amis, je suis confronté à un problème différent, ce code s'exécute sur le simulateur pas sur mon ipad2 qui a iOS v7.1.2. Si cela ne vous dérange pas, aidez-moi à résoudre ce problème.
Indra
3
@akashivskyy Très certainement, pour vous. Mais peut-être pas pour certains.
mmc
43

Pour les personnes qui utilisent la réponse de @ akashivskyy pour instancier UIViewControlleret qui ont l'exception:

erreur fatale: utilisation de l'initialiseur non implémenté 'init (coder :)' pour la classe

Conseil rapide:

Implémentez manuellement required init?(coder aDecoder: NSCoder)à votre destination UIViewControllerque vous essayez d'instancier

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

Si vous avez besoin de plus de description, veuillez vous référer à ma réponse ici

E-Riddie
la source
Si vous souhaitez utiliser un initiateur personnalisé, vous pouvez simplement appeler le super avec super.init (nibName: nil, bundle: nil) et le ouf se chargera correctement ou l'appellera avec le nom du fichier NIB.
user1700737
4
@ user1700737 J'instancie le viewController faisant référence au storyboard, qui exécute initWithCoder, pas initWithNib. Référez-vous à cette question stackoverflow.com/questions/24036393/…
E-Riddie
Salut les amis, je suis confronté à un problème différent, ce code s'exécute sur le simulateur pas sur mon ipad2 qui a iOS v7.1.2. Si cela ne vous dérange pas, aidez-moi à résoudre ce problème.
Indra
@Indra vous devez poser une autre question sur la pile, donnez-moi le lien Je serai heureux de vous aider!
E-Riddie
Sur Swift 1.2, vous devez faire init(coder aDecoder: NSCoder!)"requis". Alors maintenant, vous devez écrire ce qui suit:required init(coder aDecoder: NSCoder!)
Eduardo Viegas
18

Ce lien a les deux implémentations:

Rapide:

let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController") as UIViewController
self.presentViewController(viewController, animated: false, completion: nil)

Objectif c

UIViewController *viewController = [[UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:@"ViewController"];

Ce lien a un code pour lancer le viewcontroller dans le même storyboard

/*
 Helper to Switch the View based on StoryBoard
 @param StoryBoard ID  as String
*/
func switchToViewController(identifier: String) {
    let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(identifier) as! UIViewController
    self.navigationController?.setViewControllers([viewController], animated: false)

}
Abhijeet
la source
15

La réponse d'Akashivskyy fonctionne très bien! Mais, au cas où vous auriez du mal à revenir du contrôleur de vue présenté, cette alternative peut être utile. Ça a marché pour moi!

Rapide:

let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController") as! UIViewController
// Alternative way to present the new view controller
self.navigationController?.showViewController(vc, sender: nil)

Obj-C:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MyStoryboardName" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"someViewController"];
[self.navigationController showViewController:vc sender:nil];
Nahuel Roldan
la source
12

Le code mis à jour de Swift 4.2 est

let storyboard = UIStoryboard(name: "StoryboardNameHere", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ViewControllerNameHere")
self.present(controller, animated: true, completion: nil)
Shahzaib Maqbool
la source
7
// "Main" is name of .storybord file "
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
// "MiniGameView" is the ID given to the ViewController in the interfacebuilder
// MiniGameViewController is the CLASS name of the ViewController.swift file acosiated to the ViewController
var setViewController = mainStoryboard.instantiateViewControllerWithIdentifier("MiniGameView") as MiniGameViewController
var rootViewController = self.window!.rootViewController
rootViewController?.presentViewController(setViewController, animated: false, completion: nil)

Cela a bien fonctionné pour moi quand je l'ai mis dans AppDelegate

Maxxafari
la source
7

Si vous souhaitez le présenter de façon modale, vous devriez avoir quelque chose comme ci-dessous:

let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewControllerID")
self.showDetailViewController(vc as! YourViewControllerClassName, sender: self)
Hamid
la source
5

Je voudrais suggérer une manière beaucoup plus propre. Cela sera utile lorsque nous avons plusieurs story-boards

1.Créez une structure avec tous vos story-boards

struct Storyboard {
      static let main = "Main"
      static let login = "login"
      static let profile = "profile" 
      static let home = "home"
    }

2. Créez une extension UIStoryboard comme celle-ci

extension UIStoryboard {
  @nonobjc class var main: UIStoryboard {
    return UIStoryboard(name: Storyboard.main, bundle: nil)
  }
  @nonobjc class var journey: UIStoryboard {
    return UIStoryboard(name: Storyboard.login, bundle: nil)
  }
  @nonobjc class var quiz: UIStoryboard {
    return UIStoryboard(name: Storyboard.profile, bundle: nil)
  }
  @nonobjc class var home: UIStoryboard {
    return UIStoryboard(name: Storyboard.home, bundle: nil)
  }
}

Donnez l'identifiant du storyboard comme nom de classe et utilisez le code ci-dessous pour instancier

let loginVc = UIStoryboard.login.instantiateViewController(withIdentifier: "\(LoginViewController.self)") as! LoginViewController
vijeesh
la source
Pourquoi @nonobjc?
StackRunner
1
@StackRunner, cela ne sera pas disponible pour l'objectif c
XcodeNOOB
3

Swift 4:

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let yourVC: YourVC = storyboard.instantiateViewController(withIdentifier: "YourVC") as! YourVC
a dessiné..
la source
2

Si vous avez un Viewcontroller n'utilisant aucun storyboard / Xib, vous pouvez pousser vers ce VC particulier comme ci-dessous:

 let vcInstance : UIViewController   = yourViewController()
 self.present(vcInstance, animated: true, completion: nil)
Aks
la source
J'obtiens ceci: "ne peut pas être construit car il n'a pas d'initialiseurs accessibles".
Paul Bénéteau
les prises et autres relations établies par le storyboard sont perdues
jose920405
2

Swift 3 Storyboard

let settingStoryboard : UIStoryboard = UIStoryboard(name: "SettingViewController", bundle: nil)
let settingVC = settingStoryboard.instantiateViewController(withIdentifier: "SettingViewController") as! SettingViewController
self.present(settingVC, animated: true, completion: {

})
Giang
la source
1

Je sais que c'est un vieux fil, mais je pense que la solution actuelle (utilisant un identifiant de chaîne codé en dur pour un contrôleur de vue donné) est très sujette aux erreurs.

J'ai créé un script de construction (auquel vous pouvez accéder ici ), qui créera un moyen sûr pour le compilateur d'accéder et d'instancier des contrôleurs de vue à partir de tous les storyboards du projet donné.

Par exemple, le contrôleur de vue nommé vc1 dans Main.storyboard sera instancié comme suit :

let vc: UIViewController = R.storyboard.Main.vc1^  // where the '^' character initialize the controller
Nadav96
la source
1

Peu importe ce que j'ai essayé, cela ne fonctionnerait pas pour moi - pas d'erreurs, mais pas de nouveau contrôleur de vue sur mon écran non plus. Je ne sais pas pourquoi, mais l'enrouler dans la fonction timeout l'a finalement fait fonctionner:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.0) {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let controller = storyboard.instantiateViewController(withIdentifier: "TabletViewController")
    self.present(controller, animated: true, completion: nil)
}
Starwave
la source
1

Swift 5

let vc = self.storyboard!.instantiateViewController(withIdentifier: "CVIdentifier")
self.present(vc, animated: true, completion: nil)
Binoy jose
la source
0

J'ai créé une bibliothèque qui gérera cela beaucoup plus facilement avec une meilleure syntaxe:

https://github.com/Jasperav/Storyboardable

Changez simplement Storyboard.swift et laissez le se ViewControllersconformer Storyboardable.

J. Doe
la source