[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 621
  • Last Modified:

iOS: Firing a segue programmatically

I am creating an iOS app in Swift. I have a table view with two cells, and want to navigate to another view controller when the user clicks on one of the cells. In storyboard, to create a new segue, I control + dragged from Prototype Cell to the destination view controller. This automatically created the segue, and everything is working fine.

The problem is that I have two cells in the table (Repeat and Snooze). When the user clicks Repeat, it should take them to the Repeat View Controller, when the user clicks the Snooze cell, it should take them to the Snooze View Controller. So to handle this, in addition to the above mentioned "automatic" segue, I am also manually handling firing of Segue in didSelectRowAtIndexPath().
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        if (indexPath.item == 0)
        {
            performSegueWithIdentifier("repeatDaysSegue", sender: indexPath.item)
        }
        else if (indexPath.item == 1)
        {
            performSegueWithIdentifier("snoozeSegue", sender: indexPath.item)
        }
    }

Open in new window

It seems to be working OK, but now when the user clicks on the Repeat cell, you can see two Segues happen in the UI. Also, prepareForSegue() gets fired twice. First time the sender is a UITableViewCell, second time sender is Int.

The class code is below, what am I doing wrong?

class AddEditAlarmViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

	let array = ["Repeat", "Snooze"]

	override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return array.count;
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("settingsCustomCell")! as UITableViewCell
        cell.textLabel?.text = array[indexPath.item]
        return cell
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        if (indexPath.item == 0)
        {
            performSegueWithIdentifier("repeatDaysSegue", sender: indexPath.item)
        }
        else if (indexPath.item == 1)
        {
            performSegueWithIdentifier("snoozeSegue", sender: indexPath.item)
        }
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if (segue.identifier == "repeatDaysSegue")
        {
            let cellItem = sender as! Int
            if (array[cellItem] == "Repeat")
            {
                let repeatDaysView = segue.destinationViewController as! RepeatDaysTableViewController
                repeatDaysView.alarm = currentAlarm
            }
        }
    }
}

Open in new window

0
pzozulka
Asked:
pzozulka
  • 3
  • 3
1 Solution
 
Shahan AyyubSenior Software Engineer - iOSCommented:
Perhaps you did defined segues multiple times for the same cell. Click on view controller from the view hierarchy and go to connection inspector to identify them.
0
 
pzozulkaAuthor Commented:
There's only a single segue showing in the inspector.
0
 
lisfolksCommented:
Per your description, @pzozulka, you have one segue defined in the storyboard - yet, you have two potential segues you want to happen (repeatDaysSegue and snoozeSegue). Which is named in the storyboard, and where do you instantiate the 2nd one?
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
pzozulkaAuthor Commented:
Disregard the snoozeSegue, the point of that was to show that there could be potentially many segues created in the storbyboard. But I think that's the root of my question. How do you create multiple segues on tableview. In other words, how do you specify that if cell A is selected, I want View Controller A to be the destination segue, if cell B is selected, I want View Controller B to be the destination.

Right now, for cell A, it's working, but it's happening twice. Seems like once from the storyboard, and the second time from the code. How do I only make it happen once?
0
 
lisfolksCommented:
It appears you can only have two segues on a table row: one for tapping its accessory button, and one for tapping the rest of the row. See View Controller Programming Guide for iOS: Using Segues

What you can do, though, is set up your segue entirely in code. Delete the automatic segue. Drop everything in prepareForSegue. Then, set up the segues from your didSelectRowAtIndexPath method:
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

        if array[indexPath.item] == "Repeat"
        {
            let destViewController = storyboard?.instantiateViewControllerWithIdentifier("repeatDaysView") as! RepeatDaysTableViewController
	          destViewController.alarm = currentAlarm
	          presentViewController(destViewController, animated: true, completion: nil)
        }
        else if array[indexPath.item] == "Snooze"
        {
            let destViewController = storyboard?.instantiateViewControllerWithIdentifier("snoozeView") as! RepeatDaysTableViewController
	          // setup for snooze view...
	          presentViewController(destViewController, animated: true, completion: nil)
        }
    }

Open in new window


You might consider using a `switch` statement, rather than an `if`, if you're going to have several different cases.

As for the dual results from your current segue... I am able to replicate that situation in one of my projects. It's a learning project where I have three options, one leading to a code-only segue, one leading to a manual segue, and one leading to an automatic segue.

The manual segue is like yours, with a storyboard segue and the code call to performSegue... The automatic segue has no performSegue call, but does have action in prepareForSegue. When I change the sender to an Int value, the manual version works fine, but the automatic segue does two calls - just as you're experiencing.

Something is definitely different between the two, but I don't know what. In the storyboard, the automatic segue has a Peek & Pop attribute. The manual segue doesn't have that attribute. I remember creating them differently at the time, but... There's nothing else different in the storyboard. Hmm...

Anyway, the programmatic segues would be best in your situation because you want to do multiple from the same place with different segues (update: not identifiers, just different segues; when you do them programmatically as I described, you're not giving them identifiers).
1
 
lisfolksCommented:
Got the duplicate segue figured out!

You've got a segue going straight from your table cell to the next view controller. That's a fully "automatic" segue. You can intercept it in prepareForSegue in order to set properties, etc, if necessary. However, you don't need to do a performSegue action because that'll happen automatically when the cell is selected.

Once you added the performSegue call, iOS now does two segues: the automatic segue (giving you the TableViewCell as sender) and the manual segue (giving you the Int provided in the performSegue call).

If you want to do the performSegue call as you have it:
- delete the "repeatDaysSegue" segue currently in your storyboard.

- recreate the segue, with the same ID - but this time, take it from the view controller to the RepeatDaysTableViewController (rather than the table cell to the RepeatDaysTableViewController).

- keep the rest of your code as you have it.

Your performSegue call, then, will only run once as expected. Additional benefit: you can do many segues off your view controller, rather than being limited by directly segueing (is that a word?) from the table cell.
1
 
pzozulkaAuthor Commented:
Thanks. That's exactly it.
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now