192

My problem is that I was looking for way to use both storyboard and xib. But I can't find proper way to load and show storyboard programmatically. Project was started developing with xib, and now it's very hard to nest all xib files in storyboard. So I was looking a way to do it in code, like with alloc, init, push for viewControllers. In my case I have only one controller in storyboard: UITableViewController, which has static cells with some content I want to show. If anyone knows proper way to work both with xib and storyboard without huge refactoring, I will appreciate for any help.

Kaydell
  • 484
  • 1
  • 4
  • 14
kokoko
  • 2,705
  • 3
  • 17
  • 28

8 Answers8

386

In your storyboard go to the Attributes inspector and set the view controller's Identifier. You can then present that view controller using the following code.

UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:@"myViewController"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];
James Beith
  • 5,751
  • 3
  • 27
  • 21
  • 67
    `[sb instantiateInitialViewController]` is handy if you want to start on the scene's default view controller. – drewish Jun 15 '12 at 04:31
  • James, thank you! I've been searching for quite some time trying to figure out how to instantiate a Storyboard's view. Your answer (and kokoko's question) are most refreshing to find. – Jonathan Beebe Jul 17 '12 at 19:23
  • On James Beith's code, one must reuse that UIViewControler *vc if it is switched back and forth with the current viewcontroller. I found out the hard way that the vc sticks around and is wired to the storyboard nib until the user presses a button on the new view, and there is now a memory leak with that discarded vc from the prior incantations of this code. – SWoo Feb 06 '14 at 19:48
  • 13
    In case anyone wants to know how to do this in the app delegate, you replace the `[self presentViewcontroller]` logic with these lines in the following order: 1) `self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];` 2) `self.window.rootViewController = vc;` and 3) `[self.window makeKeyAndVisible];`. You can also probably get rid of the `modalTransitionStyle` line because this isn't a modal transition from the app delegate. – lewiguez Apr 13 '14 at 04:50
  • FYI, if you want to "push" the new storyboard instead of modally popping up, look at chaithraVeeresh's answer. – Adam Johns Oct 27 '14 at 18:13
  • Remember to cast the view controller to your view controller class if you want to set any params which you'd normally do in prepareForSegue. – LordParsley Apr 24 '18 at 19:05
  • How to call the cocoa touch class file for that ViewController – Ephrim Daniel Feb 13 '19 at 09:37
86

Swift 3

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "viewController")
self.navigationController!.pushViewController(vc, animated: true)

Swift 2

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("viewController")
self.navigationController!.pushViewController(vc, animated: true)

Prerequisite

Assign a Storyboard ID to your view controller.

Storyboard ID

IB > Show the Identity inspector > Identity > Storyboard ID

Swift (legacy)

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("viewController") as? UIViewController
self.navigationController!.pushViewController(vc!, animated: true)

Edit: Swift 2 suggested in a comment by Fred A.

if you want to use without any navigationController you have to use like following :

    let Storyboard  = UIStoryboard(name: "Main", bundle: nil)
    let vc = Storyboard.instantiateViewController(withIdentifier: "viewController")
    present(vc , animated: true , completion: nil)
Community
  • 1
  • 1
SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
18

In attribute inspector give the identifier for that view controller and the below code works for me

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
DetailViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:@"DetailViewController"];
[self.navigationController pushViewController:detailViewController animated:YES];
Ray Andison
  • 276
  • 1
  • 10
chaithraVeeresh
  • 258
  • 3
  • 11
5

Try this

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:@"Login"];

[[UIApplication sharedApplication].keyWindow setRootViewController:vc];
Philip K. Adetiloye
  • 3,102
  • 4
  • 37
  • 63
2

in swift
NavigationController and pushController you can replace for

present(vc, animated:true , completion: nil)
Tarik
  • 539
  • 7
  • 16
2

For swift 4 and 5, you can do this. Good practice is set name of Storyboard equal to StoryboardID.

enum StoryBoardName{
   case second = "SecondViewController"
}
extension UIStoryboard{
   class func load(_ storyboard: StoryBoardName) -> UIViewController{
      return UIStoryboard(name: storyboard.rawValue, bundle: nil).instantiateViewController(withIdentifier: storyboard.rawValue)
   }
}

and then you can load your Storyboard in your ViewController like this:

class MyViewController: UIViewController{
     override func viewDidLoad() {
        super.viewDidLoad()
        guard let vc = UIStoryboard.load(.second) as? SecondViewController else {return}
        self.present(vc, animated: true, completion: nil)
     }

}

When you create a new Storyboard just set the same name on StoryboardID and add Storyboard name in your enum "StoryBoardName"

gandhi Mena
  • 2,115
  • 1
  • 19
  • 20
1

You can always jump right to the root controller:

UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateInitialViewController];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];
user938797
  • 167
  • 3
  • 15
1

The extension below will allow you to load a Storyboard and it's associated UIViewController. Example: If you have a UIViewController named ModalAlertViewController and a storyboard named "ModalAlert" e.g.

let vc: ModalAlertViewController = UIViewController.loadStoryboard("ModalAlert")

Will load both the Storyboard and UIViewController and vc will be of type ModalAlertViewController. Note Assumes that the storyboard's Storyboard ID has the same name as the storyboard and that the storyboard has been marked as Is Initial View Controller.

extension UIViewController {
    /// Loads a `UIViewController` of type `T` with storyboard. Assumes that the storyboards Storyboard ID has the same name as the storyboard and that the storyboard has been marked as Is Initial View Controller.
    /// - Parameter storyboardName: Name of the storyboard without .xib/nib suffix.
    static func loadStoryboard<T: UIViewController>(_ storyboardName: String) -> T? {
        let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
        if let vc = storyboard.instantiateViewController(withIdentifier: storyboardName) as? T {
            vc.loadViewIfNeeded() // ensures vc.view is loaded before returning
            return vc
        }
        return nil
    }
}
Norman
  • 3,020
  • 22
  • 21