kokoko
kokoko

Reputation: 2705

How can I load storyboard programmatically from class?

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.

Upvotes: 192

Views: 154186

Answers (8)

gandhi Mena
gandhi Mena

Reputation: 2293

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"

Upvotes: 2

Norman
Norman

Reputation: 3215

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

Upvotes: 1

SwiftArchitect
SwiftArchitect

Reputation: 48532

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)

Upvotes: 86

user938797
user938797

Reputation: 177

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];

Upvotes: 1

Tarik
Tarik

Reputation: 549

in swift
NavigationController and pushController you can replace for

present(vc, animated:true , completion: nil)

Upvotes: 2

Philip K. Adetiloye
Philip K. Adetiloye

Reputation: 3270

Try this

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

[[UIApplication sharedApplication].keyWindow setRootViewController:vc];

Upvotes: 5

chaithraVeeresh
chaithraVeeresh

Reputation: 258

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];

Upvotes: 18

James Beith
James Beith

Reputation: 5761

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];

Upvotes: 386

Related Questions