Swift
performSegueWithIdentifier
troubleshooting
iOS development
Xcode

Swift performSegueWithIdentifier not working

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

performSegue(withIdentifier:sender:) fails silently or crashes when the segue identifier does not match the storyboard, the segue is not connected to the correct view controller, or the method is called before the view is loaded. The most common causes are a typo in the identifier string, a missing segue connection in Interface Builder, or calling the method from a view controller that is not in the navigation hierarchy. Check the storyboard identifier, verify the source view controller, and use prepare(for:sender:) for data passing.

The Basic Call

swift
// Trigger a segue programmatically
performSegue(withIdentifier: "showDetail", sender: self)

This calls the segue named "showDetail" from the current view controller. If it fails, the error is typically one of the issues below.

Cause 1: Wrong Segue Identifier

swift
1// Storyboard has identifier "ShowDetail" (capital S)
2// Code uses "showDetail" (lowercase s) — DOES NOT MATCH
3performSegue(withIdentifier: "showDetail", sender: self)
4// Crash: has no segue with identifier 'showDetail'
5
6// Fix: match the exact string from the storyboard
7performSegue(withIdentifier: "ShowDetail", sender: self)
8
9// Better: use a constant to prevent typos
10enum Segue {
11    static let showDetail = "ShowDetail"
12    static let showSettings = "ShowSettings"
13    static let showProfile = "ShowProfile"
14}
15
16performSegue(withIdentifier: Segue.showDetail, sender: self)

The identifier is case-sensitive. A single character mismatch causes a runtime crash with the message has no segue with identifier.

Cause 2: Segue Not Connected in Storyboard

swift
1// The segue exists in the storyboard but is connected to a different view controller
2// Or the segue was deleted and recreated without updating the identifier
3
4// Verify in Xcode:
5// 1. Open Main.storyboard
6// 2. Click on the source view controller
7// 3. Open the Connections Inspector (right panel)
8// 4. Check that the segue appears under "Triggered Segues"
9// 5. Verify the identifier in the Attributes Inspector

If the segue line is not visible between the two view controllers in the storyboard, the connection is missing. Control-drag from the source to the destination to create it.

Cause 3: Calling Before View Is Loaded

swift
1class MyViewController: UIViewController {
2
3    override init(nibName: String?, bundle: Bundle?) {
4        super.init(nibName: nibName, bundle: bundle)
5        // WRONG: view is not loaded yet, no navigation stack
6        performSegue(withIdentifier: "ShowDetail", sender: self)
7    }
8
9    override func viewDidLoad() {
10        super.viewDidLoad()
11        // RISKY: view is loaded but may not be in the window hierarchy
12        // performSegue may silently fail
13    }
14
15    override func viewDidAppear(_ animated: Bool) {
16        super.viewDidAppear(animated)
17        // CORRECT: view is fully visible and in the navigation stack
18        performSegue(withIdentifier: "ShowDetail", sender: self)
19    }
20}

A segue can only be performed when the view controller is part of the view hierarchy. Call performSegue in viewDidAppear or in response to user actions, not in init or viewDidLoad.

Cause 4: Wrong Source View Controller

swift
1// Segue is connected FROM ViewControllerA TO ViewControllerB
2// But you are calling performSegue from ViewControllerC
3
4class ViewControllerC: UIViewController {
5    func goToDetail() {
6        // This fails because ViewControllerC has no segue named "ShowDetail"
7        performSegue(withIdentifier: "ShowDetail", sender: self)
8    }
9}
10
11// Fix: ensure the segue is connected from the correct source view controller

Each segue belongs to a specific source view controller. You can only trigger it from that controller.

Passing Data with prepare(for:sender:)

swift
1class ListViewController: UIViewController {
2
3    var items: [Item] = []
4    var selectedItem: Item?
5
6    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
7        selectedItem = items[indexPath.row]
8        performSegue(withIdentifier: "ShowDetail", sender: self)
9    }
10
11    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
12        if segue.identifier == "ShowDetail" {
13            if let detailVC = segue.destination as? DetailViewController {
14                detailVC.item = selectedItem
15            }
16        }
17    }
18}

prepare(for:sender:) is called automatically before the segue transition. Use it to configure the destination view controller.

Modern Alternative: Programmatic Navigation

swift
1// Instead of storyboard segues, navigate programmatically
2class ListViewController: UIViewController {
3
4    func showDetail(item: Item) {
5        let detailVC = DetailViewController()
6        detailVC.item = item
7        navigationController?.pushViewController(detailVC, animated: true)
8    }
9
10    // Or instantiate from storyboard without segues
11    func showDetailFromStoryboard(item: Item) {
12        let storyboard = UIStoryboard(name: "Main", bundle: nil)
13        if let detailVC = storyboard.instantiateViewController(
14            withIdentifier: "DetailVC"
15        ) as? DetailViewController {
16            detailVC.item = item
17            navigationController?.pushViewController(detailVC, animated: true)
18        }
19    }
20}

Programmatic navigation avoids segue identifier issues entirely and makes data passing explicit. Many modern iOS codebases prefer this over storyboard segues.

Debugging Tips

swift
1// 1. Print all segues to verify they exist
2override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
3    print("Segue triggered: \(segue.identifier ?? "nil")")
4    print("Destination: \(type(of: segue.destination))")
5}
6
7// 2. Check if the view controller is in the hierarchy
8print("Parent: \(String(describing: parent))")
9print("Navigation: \(String(describing: navigationController))")
10print("Is in window: \(view.window != nil)")
11
12// 3. Override shouldPerformSegue to prevent invalid transitions
13override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
14    if identifier == "ShowDetail" && selectedItem == nil {
15        print("Cannot show detail: no item selected")
16        return false
17    }
18    return true
19}

Common Pitfalls

  • Segue identifier typo: The identifier string is case-sensitive and must exactly match the storyboard. Use constants or enums instead of string literals to catch typos at compile time.
  • Calling performSegue from viewDidLoad: The view controller may not be in the window hierarchy yet. The segue may fail silently or crash. Use viewDidAppear or trigger from user actions (button taps, table cell selection).
  • Segue connected to the wrong view controller: In complex storyboards, it is easy to connect a segue from the wrong source. Verify in the Connections Inspector that the segue appears under the correct view controller's "Triggered Segues."
  • Not implementing prepare(for:sender:) for data passing: Without prepare, the destination view controller receives no data from the source. The segue still transitions, but the destination appears empty or with default values.
  • Using deprecated performSegueWithIdentifier:sender: syntax: The Objective-C method name performSegueWithIdentifier:sender: was renamed to performSegue(withIdentifier:sender:) in Swift 3+. Using the old name causes a compile error in modern Swift.

Summary

  • Verify the segue identifier matches exactly (case-sensitive) between code and storyboard
  • Ensure the segue is connected from the correct source view controller in Interface Builder
  • Call performSegue only after the view is in the hierarchy (viewDidAppear, not viewDidLoad)
  • Use prepare(for:sender:) to pass data to the destination view controller
  • Use constants or enums for segue identifiers to prevent typos
  • Consider programmatic navigation (pushViewController) as a more maintainable alternative to storyboard segues

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.