93

I'd like to navigate from one view controller to another. How can I convert the following Objective-C code into Swift?

UIViewController *viewController = [[self storyboard] instantiateViewControllerWithIdentifier:@"Identifier"];
UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:viewController];
[self.navigationController pushViewController:navi animated:YES];
vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
sathish
  • 1,180
  • 1
  • 9
  • 9

16 Answers16

230

Create a swift file (SecondViewController.swift) for the second view controller and in the appropriate function type this:

let secondViewController = self.storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as SecondViewController
self.navigationController.pushViewController(secondViewController, animated: true)


Swift 2+

let mapViewControllerObj = self.storyboard?.instantiateViewControllerWithIdentifier("MapViewControllerIdentifier") as? MapViewController
self.navigationController?.pushViewController(mapViewControllerObj!, animated: true)

Swift 4

let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "IKDetailVC") as? IKDetailVC
self.navigationController?.pushViewController(vc!, animated: true)
Imrul Kayes
  • 618
  • 1
  • 10
  • 17
Audrey Sobgou Zebaze
  • 2,840
  • 2
  • 19
  • 9
  • 1
    @audrey,Hi, how to set navigationController? – Sanjivani Jun 12 '14 at 05:43
  • 1
    @Sanjivani, Hi your view controller can be created with Storyboard and assign your firstViewController as rootViewController.Your navigation Controller (swift) class will look like this: `import UIKit` `class SwiftNavigationController: UINavigationController { init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) // Custom initialization }`` override func viewDidLoad() { super.viewDidLoad() }` – Audrey Sobgou Zebaze Jun 12 '14 at 09:09
  • How do you assign the first view controller as the "rootViewController" ? – Kokodoko Jul 25 '14 at 10:34
  • Are you using storyboard ? what kind of project template do you have ? – Audrey Sobgou Zebaze Jul 27 '14 at 08:44
  • 3
    I also had same problem, I was stuck at how to navigate from one ViewController to another. When I tried this code, I am getting this error: `unexpectedly found nil while unwrapping an Optional value` at second line of your code. Please help – Raghavendra Aug 08 '14 at 06:08
  • 1
    I am having an issue with the animated: parameter like so: "Cannot convert the expression's type '$T7??' to type 'BooleanLiteralConvertible'". – Morkrom Dec 29 '14 at 19:11
  • 2
    You need to make sure your controllers are embedded in a NavigationController for this to work, otherwise you will get errors. – kakubei Apr 07 '15 at 10:31
  • @AkashRaghani did you set the Storyboard ID in Storyboard -> identity inspector ? – Audrey Sobgou Zebaze Sep 21 '15 at 15:27
  • unexpectedly found nil while unwrapping an Optional value – Abhishek Thapliyal Mar 04 '16 at 21:32
  • Why have you removed the `?` from `self.storyboard`? don't you need to unwrap it? – mfaani Sep 18 '16 at 22:07
35

In my experience navigationController was nil so I changed my code to this:

let next = self.storyboard?.instantiateViewControllerWithIdentifier("DashboardController") as! DashboardController
self.presentViewController(next, animated: true, completion: nil)

Don't forget to set ViewController StoryBoard Id in StoryBoard -> identity inspector

Forge
  • 6,538
  • 6
  • 44
  • 64
Mojtaba Yeganeh
  • 2,788
  • 1
  • 30
  • 49
18

If you don't want the back button to appear (which was my case, because I wanted to present after a user logged in) here is how to set the root of the nav controller:

let vc = self.storyboard?.instantiateViewControllerWithIdentifier("YourViewController") as! YourViewController
        let navigationController = UINavigationController(rootViewController: vc)
        self.presentViewController(navigationController, animated: true, completion: nil)
Keith Holliday
  • 1,692
  • 21
  • 15
16

SWIFT 3.01

let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "Conversation_VC") as! Conversation_VC
self.navigationController?.pushViewController(secondViewController, animated: true)
Yaroslav Dukal
  • 3,894
  • 29
  • 36
8

In swift 4.0

var viewController: UIViewController? = storyboard().instantiateViewController(withIdentifier: "Identifier")
var navi = UINavigationController(rootViewController: viewController!)
navigationController?.pushViewController(navi, animated: true)
perror
  • 7,071
  • 16
  • 58
  • 85
Protocol
  • 1,696
  • 13
  • 30
5

In Swift 4.1 and Xcode 10

Here AddFileViewController is second view controller.

Storyboard id is AFVC

let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)

//OR

//If your VC is DashboardViewController
let dashboard = self.storyboard?.instantiateViewController(withIdentifier: "DBVC") as! DashboardViewController
self.navigationController?.pushViewController(dashboard, animated: true)

If required use thread.

Ex:

DispatchQueue.main.async { 
    let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
    self.present(next, animated: true, completion: nil) 
}

If you want move after some time.

EX:

//To call or execute function after some time(After 5 sec)
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
    self.present(next, animated: true, completion: nil) 
} 
Naresh
  • 16,698
  • 6
  • 112
  • 113
5
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let home = storyBoard.instantiateViewController(withIdentifier: "HOMEVC") as! HOMEVC
navigationController?.pushViewController(home, animated: true);
Shanu Singh
  • 365
  • 3
  • 16
3

Swift 3

let secondviewController:UIViewController =  self.storyboard?.instantiateViewController(withIdentifier: "StoryboardIdOfsecondviewController") as? SecondViewController

self.navigationController?.pushViewController(secondviewController, animated: true)
Saurav Kumar
  • 256
  • 3
  • 6
3

In swift 3

let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "NextViewController") as! NextViewController        
self.navigationController?.pushViewController(nextVC, animated: true)
General Failure
  • 2,421
  • 4
  • 23
  • 49
Zeeshan
  • 51
  • 5
2
let objViewController = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
self.navigationController?.pushViewController(objViewController, animated: true)
Pang
  • 9,564
  • 146
  • 81
  • 122
  • Could you please explain shortly what your code does, why it solves the problem and how it's different from all the other answers. – JJJ Aug 09 '17 at 06:14
  • here i am using storyboard id as identifier . Via the reference (objViewController) push the control to the View Controller class – Davender Verma Aug 09 '17 at 12:06
2

Swift 5

Use Segue to perform navigation from one View Controller to another View Controller:

performSegue(withIdentifier: "idView", sender: self)

This works on Xcode 10.2.

Jerry Chong
  • 7,954
  • 4
  • 45
  • 40
2

Better practices Swift 5.0

More reusable and readable

Create a protocol

protocol Storyboarded { }

Now create an extension of the protocol

extension Storyboarded where Self: UIViewController {
    
    static func instantiateFromMain() -> Self {
        let storyboardIdentifier = String(describing: self)
        // `Main` can be your stroyboard name.
        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
        
        guard let vc = storyboard.instantiateViewController(withIdentifier: storyboardIdentifier) as? Self else {
            fatalError("No storyboard with this identifier ")
        }
        return vc
    }
}
// Make a ViewController extension to use on all of your ViewControllers
extension UIViewController: Storyboarded {}

How to use

  let vc = MyViewController.instantiateFromMain()
  //here you can pass any data to the next view controller. for example we have a variable with name `myString` in our next view contoller and we want to pass the data my `self viewController`
  vc.myString = "This string passed by MyViewController"
  self.navigationController?.pushViewController(vc, animated: true)

Note:- You need to give the same identifier on the storyboard as your UIViewController class has. Check the example below

enter image description here

Rashid Latif
  • 2,809
  • 22
  • 26
2

For Swift 4 & 5 Users can use this way

Swift 5

 let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
 let vc = storyBoard.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
 self.navigationController?.pushViewController(vc, animated: true)

Swift 4

let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "YourViewController") as? YourViewController 
self.navigationController?.pushViewController(vc!, animated: true)
Navdeep Paliwal
  • 349
  • 3
  • 7
1

Swift 4

You can switch the screen by pushing navigation controller first of all you have to set the navigation controller with UIViewController

let vc = self.storyboard?.instantiateViewController(withIdentifier: "YourStoryboardID") as! swiftClassName

self.navigationController?.pushViewController(vc, animated: true)
Azharhussain Shaikh
  • 1,654
  • 14
  • 17
1

In AppDelegate you can write like this...

var window: UIWindow?

fileprivate let navigationCtrl = UINavigationController()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    self.createWindow()

    self.showLoginVC()

    return true
}

func createWindow() {
    let screenSize = UIScreen.main.bounds
    self.window = UIWindow(frame: screenSize)
    self.window?.backgroundColor = UIColor.white
    self.window?.makeKeyAndVisible()
    self.window?.rootViewController = navigationCtrl
}

func showLoginVC() {
    let storyboardBundle = Bundle.main
    // let storyboardBundle = Bundle(for: ClassName.self) // if you are not using main application, means may be you are crating a framework or library you can use this statement instead
    let storyboard = UIStoryboard(name: "LoginVC", bundle: storyboardBundle)
    let loginVC = storyboard.instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
    navigationCtrl.pushViewController(loginVC, animated: false)
}
KPK
  • 160
  • 1
  • 7
-1

Update for Swift 5:

    let next = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController

    self.present(next, animated: true, completion: nil)

Don't forget to update the Storyboard ID for both View Controllers!

David K
  • 73
  • 4