319

Issue

I started taking a look of the new Swift on Xcode 6, and I tried some demo projects and tutorials. Now I am stuck at:

Instantiating and then presenting a viewController from a specific storyboard

Objective-C Solution

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

How to achieve this on Swift?

Community
  • 1
  • 1
E-Riddie
  • 14,052
  • 7
  • 47
  • 70

16 Answers16

689

This answer was last revised for Swift 5.4 and iOS 14.5 SDK.


It's all a matter of new syntax and slightly revised APIs. The underlying functionality of UIKit hasn't changed. This is true for a vast majority of iOS SDK frameworks.

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

Make sure to set myVCID inside the storyboard, under "Storyboard ID."

akashivskyy
  • 40,844
  • 15
  • 103
  • 113
  • 3
    You can even omit the `;`! ;) Would you mind elaborating on the `as UIViewController`? Why is that necessary? – Sebastian Wramba Jun 04 '14 at 11:23
  • 5
    `as` keyword is used for typecasting. It's the same as `(UIViewController *)anObject` in objective c – Garoal Jun 04 '14 at 11:25
  • 1
    Yeah I know I can omit them but that's a part of the long habbit. :D As `instantiateViewControllerWithIdentifier` returns `AnyObject` (`id` equivalent in Swift) and I declare `vc` as `UIViewController`, I have to typecast `AnyObject` to `UIViewController`. – akashivskyy Jun 04 '14 at 11:27
  • Hi Friends, i am facing some different issue, This code run on simulator not on my ipad2 which having iOS v7.1.2. If you dont mind help me to resolve this issue. – Indra Sep 14 '14 at 03:25
  • the "as UIViewController" can also be "as CustomViewControllerSubclass". You're not always going to want to instantiate *just* a UIViewController from a storyboard. – mmc Dec 25 '14 at 23:27
  • 3
    @akashivskyy Most definitely, to you. But maybe not to some. – mmc Dec 25 '14 at 23:33
  • with Swift 1.2, the `as` should be changed to `as!` (more info: https://developer.apple.com/swift/blog/?id=23) – matt--- Apr 18 '15 at 06:15
  • As of Swift 2 `instantiateViewControllerWithIdentifier` returns `UIViewController` so you don't need to unroll anymore. So things simplify: `let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil); let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController"); self.presentViewController(vc, animated: true, completion: nil)` – Adam Sep 11 '15 at 17:13
  • for ios9 as! UIViewController no need it "Forced cast of 'UIViewController' to same type has no effect" – iluvatar_GR Sep 30 '15 at 04:59
  • If I go to second viewController in tabBarController, How do I do? If I direct to second viewController than does not show TavBarController. –  Nov 01 '16 at 04:32
  • Is it necessary to instantiate the storyboard object each time or I thing it can be made static to reuse it. Am I correct with this approach. – Shubham Ojha Nov 14 '17 at 14:51
  • @akashivskyy In the new syntax. I don't need the extra "as UINavigationController" then? In let controller = storyboard.instantiateViewController(withIdentifier: "someViewController") – Cons Bulaquena Apr 26 '18 at 09:41
  • I don't think completion is required. – Daniel Springer Nov 12 '18 at 22:03
  • it's better to use with navigation `self.navigationController?.show(controller, sender: nil)` – user25 Mar 08 '19 at 15:40
  • @user25 It's not. – akashivskyy Mar 09 '19 at 23:03
  • yes, it is. if you have more than one controller then you have to add navigation controller – user25 Mar 10 '19 at 10:26
  • it showing me condition of iOS 13 ?? how can I do for iOS 12 ? Thank You. – Yogesh Patel Oct 04 '19 at 09:30
43

For people using @akashivskyy's answer to instantiate UIViewController and are having the exception:

fatal error: use of unimplemented initializer 'init(coder:)' for class

Quick tip:

Manually implement required init?(coder aDecoder: NSCoder) at your destination UIViewController that you are trying to instantiate

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

If you need more description please refer to my answer here

E-Riddie
  • 14,052
  • 7
  • 47
  • 70
  • If you want to use custom initiator you can just call the super with super.init(nibName: nil, bundle: nil) and the whew will load fine or do call it with the name of them NIB file. – Lars Christoffersen Jun 09 '14 at 22:58
  • 4
    @user1700737 I am instantiating the viewController referring to storyboard, which executes initWithCoder, not initWithNib. Refer to this question http://stackoverflow.com/questions/24036393/fatal-error-use-of-unimplemented-initializer-initcoder-for-class/24036440#24036440 – E-Riddie Jun 10 '14 at 06:15
  • Hi Friends, i am facing some different issue, This code run on simulator not on my ipad2 which having iOS v7.1.2. If you dont mind help me to resolve this issue. – Indra Sep 14 '14 at 03:26
  • @Indra you need to ask another question on stack, give me the link Ill be happy to help you! – E-Riddie Sep 14 '14 at 07:35
  • On Swift 1.2 you must make `init(coder aDecoder: NSCoder!)` "required". So now you have to write the following: `required init(coder aDecoder: NSCoder!)` – Eduardo Viegas Jun 12 '15 at 17:35
20

This link has both the implementations:

Swift:

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

Objective C

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

This link has code for initiating viewcontroller in the same 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)

}
Community
  • 1
  • 1
Abhijeet
  • 7,483
  • 3
  • 60
  • 70
15

akashivskyy's answer works just fine! But, in case you have some trouble returning from the presented view controller, this alternative can be helpful. It worked for me!

Swift:

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
  • 573
  • 7
  • 12
13

Swift 4.2 updated code is

let storyboard = UIStoryboard(name: "StoryboardNameHere", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ViewControllerNameHere")
self.present(controller, animated: true, completion: nil)
Shahzaib Maqbool
  • 1,331
  • 13
  • 22
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)

This worked fine for me when i put it in AppDelegate

Maxxafari
  • 71
  • 1
  • 2
7

If you want to present it modally, you should have something like bellow:

let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewControllerID")
self.showDetailViewController(vc as! YourViewControllerClassName, sender: self)
Hamid
  • 2,272
  • 1
  • 25
  • 41
6

I would like to suggest a much cleaner way. This will be useful when we have multiple storyboards

1.Create a structure with all your storyboards

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

2. Create a UIStoryboard extension like this

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)
  }
}

Give the storyboard identifier as the class name, and use the below code to instantiate

let loginVc = UIStoryboard.login.instantiateViewController(withIdentifier: "\(LoginViewController.self)") as! LoginViewController
Velociround
  • 502
  • 6
  • 17
vijeesh
  • 1,212
  • 1
  • 16
  • 31
3

Swift 4:

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let yourVC: YourVC = storyboard.instantiateViewController(withIdentifier: "YourVC") as! YourVC
drew..
  • 2,384
  • 2
  • 14
  • 19
2

If you have a Viewcontroller not using any storyboard/Xib, you can push to this particular VC like below call :

 let vcInstance : UIViewController   = yourViewController()
 self.present(vcInstance, animated: true, completion: nil)
Aks
  • 4,339
  • 1
  • 33
  • 32
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: {

})
Nathan Tuggy
  • 2,239
  • 27
  • 28
  • 36
Giang
  • 3,031
  • 26
  • 26
1

I know it's an old thread, but I think the current solution (using hardcoded string identifier for given view controller) is very prone to errors.

I've created a build time script (which you can access here), which will create a compiler safe way for accessing and instantiating view controllers from all storyboard within the given project.

For example, view controller named vc1 in Main.storyboard will be instantiated like so:

let vc: UIViewController = R.storyboard.Main.vc1^  // where the '^' character initialize the controller
Nadav96
  • 1,051
  • 1
  • 14
  • 25
1

No matter what I tried, it just wouldn't work for me - no errors, but no new view controller on my screen either. Don't know why, but wrapping it in timeout function finally made it work:

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
  • 2,051
  • 1
  • 16
  • 22
1

Swift 5

let vc = self.storyboard!.instantiateViewController(withIdentifier: "CVIdentifier")
self.present(vc, animated: true, completion: nil)
Binoy jose
  • 413
  • 4
  • 9
0

I created a library that will handle this much more easier with better syntax:

https://github.com/Jasperav/Storyboardable

Just change Storyboard.swift and let the ViewControllers conform to Storyboardable.

J. Doe
  • 9,757
  • 4
  • 42
  • 83
0
guard let vc = storyboard?.instantiateViewController(withIdentifier: "add") else { return }
        vc.modalPresentationStyle = .fullScreen
        present(vc, animated: true, completion: nil)
Ironkey
  • 2,492
  • 1
  • 5
  • 27
MdYaz
  • 11
  • Please add some explanation to your answer. Explaining the underlying logic is more important than just giving the code. It helps the author and other readers fix this and similar issues themselves while giving them the clues to the knowledge they need to expand their programming skills. – Ironkey Nov 12 '20 at 19:26