27
votes

Based on the Stanford iOS course I am playing with modal view controllers. In the demo they have a button that would launch a modal view and when it is clicked the function prepareForSegue is called. I mimicked the code and implementation into my project with the only difference is that my demo is on an iPhone storyboard and theirs is on the iPad.

I noticed that while my modal view controller is coming up, it does not call prepareForSegue prior to that. I searched the Stanford project to see where they may register any segue behavior before prepareForSegue is called but there is no evidence. Can anyone shed some light on this. I searched stack overflow and all I found were that users were missing the call implementation of performSegueWithIdentifier. However, in the Stanford demo they never do that.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier hasPrefix:@"Create Label"]) {
        AskerViewController *asker = (AskerViewController *)segue.destinationViewController;
        asker.question = @"What do you want your label to say?";
        asker.answer = @"Label Text";
        asker.delegate = self;
    }

}

Here is an example of there storyboard: enter image description here

Here is an example of my storyboard: enter image description here

In the debugger when I stop in the Stanford Demo code the call stack shows that the storyboard is performing a segue action, what do I need to configure in my storyboard to achieve the same result? enter image description here

10
How do you know prepareForSegue: is not being called? I bet it is being called. The only way to be sure is to put a breakpoint on the very first statement in it. Have you done that?matt
Yes I have, that is why I am asking the question. In my demo, my prepreForSegue is not being called, but in the Stanford demo it is.Amro Younes

10 Answers

35
votes

Well, as it turns out, my view controller where button calls the modal view did not have the right class where prepareForSegue is implemented. It was the default UIViewController instead of my custom class.

The way I figured it out was by putting a break point in viewDidLoad and even that was not breaking and thus I suspected that in the storyboard I did not have the right class associated with the view where the button is implemented.

15
votes

For others with this problem, if you are now using Swift 3 having the following function will not throw errors as it is the correct syntax but it will not work because it is the Swift 2 function:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // code
}

You must update to Swift 3 "prepare" function for it to work for segues:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // code
}
11
votes

When hooking up an automatic segue for a table view, there is, in addition to Amro's answer (not assigning your corresponding subclass), another two cases where prepareForSegue might not be called. Ensure you've:

  1. hooked up the segue from the table view prototype cell, not the table view controller.

  2. used a segue from under the "Selection Segue" group in the segue connection pop-up menu, not one under "Accessory Action".

Hooking up automatic segues

[Click image to enlarge]

5
votes

Whether its an Modal or Push Segue below code will always be called

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"Create Label"]) {
        SignUpViewController *asker = segue.destinationViewController;
    }
}
2
votes

I had a similar problem with UICollectionViewCell as the source of segue.
It seems that for the storyboard segue to work (without performSegueWithIdentifier) it's required that you have a custom subclass of UICollectionViewCell, and use it as a Class for the CollectionViewCell on the story board.

2
votes

I had a similar issue.

The thought process was:

  1. make sure you have the correct method signature. It has changed in Swift 3.
  2. Then make sure the way you have hooked up the button (or whatever that triggers the segue) matches with the way you have hooked the segue in storyboard. Sometimes you call a button, but haven't properly hooked up the segue from that button to the destination viewcontroller.
  3. Be sure the identifier of the segue is correct. Though this isn't the reason the prepareForSegue doesn't get called, this only the reason that a specific segue isn't called.
2
votes

In my case, it ocured because my controller was extending another controller (Eureka Form View Controller = FormViewController) witch has implemented the performSegue function like this:

open override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // code
}

My function was implemented like this:

func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // code
}

To solve this, i just added override before:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // code
}

Voila!

1
votes

In my case, I did not set the module under the name of the class in the storyboard of the view controller that contains the segue. It was set to none and once I clicked in the module field it set to the correct project / module and resolved the issue.

0
votes

In my case, I have a base class for several view controllers in my project. That base class has an implementation of prepareForSegue() which wasn't getting called in every case. The problem was that in one of my view controllers that inherits from the base class and overrides its prepareForSegue() implementation, I forgot to call super.prepareForSegue().

-1
votes

Firstly you have to select on your button + ctrl drag item to you view controller choose selection segue .Later, you have to name segue identifier properly.

Don't connect to one view controller to other view controller. import UIKit.framework for this Then this method will get called.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"identifierName"])
    {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        ExampleViewController *destViewController = segue.destinationViewController;
    }
}