Can't pass data to another View Controller with the prepareForSegue method if that View Controller is not the one immediately being segued to

StackOverflow https://stackoverflow.com/questions/20964924

Question

Today I learned how to pass data between View Controllers.

I have 3 View Controllers and they all use Push segues and they are visited by the user in this order: SignUp View Controller > Verification View Controller > Pin Submit View Controller

Anyways, earlier today I was able to successfully pass data from the Signup View Controller to the Verification View Controller.

I then realized that I needed to pass some data that is generated on the SignUp View Controller to the Pin Submit View Controller. I tried using my normal prepareForSegue method implementation and I could not get it to work for the past hour.

So I got frustrated, and set it up so that the data is passed from the SignUp View Controller, to the Verification View Controller, and then to the Pin Submit View Controller. Even though the Verification View Controller does not need or have any use for the data I am passing.

Sure enough it worked PERFECTLY! But what is frustrating is I don't understand why I couldn't just use my normal method and pass the data from the SignUp View Controller straight to the Pin Submit View Controller when the Verification View Controller isn't even going to use the data.

Is it because I am using the prepareForSegue method?

Here's an example of what I've been using. Here is my prepareForSegue implementation in my "sending" View Controller's main file:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:self {


if ([segue.identifier isEqualToString:@"signupToVerificationSegue"]) {


    VerificationViewController *verifyViewController = segue.destinationViewController;


    PinSubmitViewController *pinViewController = [[PinSubmitViewController alloc]init];


    verifyViewController.uniqueVerificationCode = _uniqueVerificationCode;
    verifyViewController.userSubmittedUsername = _userSubmittedUsername;

    pinViewController.userSubmittedUsername = _userSubmittedUsername;

}
}

And then here is an IBAction method implemetation that is hooked up to a UIButton and is responsible for performing the actual segue aka calling BOTH the prepareForSegue method that we implemented above and the performSegueWithIdentifier method:

- (IBAction)didTapSignup:(id)sender {

NSString *user = [_usernameEntry text];
NSString *pass = [_passwordEntry text];
NSString *email = [_emailEntry text];

self.userSubmittedUsername = user;

int randomCode = arc4random() % 9000 + 1000;

NSString *uniqueVerificationCode = [[NSString alloc]initWithFormat:@"%d", randomCode];

self.uniqueVerificationCode = uniqueVerificationCode;

PinSubmitViewController *pinViewController = [[PinSubmitViewController alloc]init];
pinViewController.userSubmittedUsername = _userSubmittedUsername;

NSLog(@"%@", _userSubmittedUsername);
NSLog(@"%@", user);
NSLog(@"%@", pass);
NSLog(@"%@", email);
NSLog(@"Random 4 Digit Code: %@", uniqueVerificationCode);

if ([user length] < 4 || [pass length] < 4) {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Invalid Entry" message:@"Username and Password must both be at least 4 characters long." delegate:self cancelButtonTitle:@"Okay" otherButtonTitles:nil];
    [alert show];
} else if ([email length] < 8) {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Invalid Entry" message:@"Please enter your email address." delegate:self cancelButtonTitle:@"Okay" otherButtonTitles:nil];
    [alert show];
} else {

    [_activityIndicator startAnimating];

    PFUser *newUser = [PFUser user];
    newUser.username = user;
    newUser.password = pass;
    newUser.email = email;


    NSLog(@"SEE IF THE PROPERTY WORKED: %@", self.uniqueVerificationCode);
    newUser[@"verificationCode"] = self.uniqueVerificationCode;

    [newUser signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
        [_activityIndicator stopAnimating];
        if (error) {
            NSString *errorString = [[error userInfo] objectForKey:@"error"];
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:self cancelButtonTitle:@"Okay" otherButtonTitles:nil];
            [alert show];
        } else {

NSLog(@"No errors in signup process");

UIStoryboardSegue *segue = [[UIStoryboardSegue alloc]init];

[self prepareForSegue:segue sender:self];

[self performSegueWithIdentifier:@"signupToVerificationSegue" sender:self];


}
}];
}

Any help with this and insight into why I cannot achieve this the way I want to would be greatly appreciated thank you!

Was it helpful?

Solution

What really happens in prepareForSegue method is that it notifies the View Controller that a segue is about to be performed.

So, you can access the destinationViewController using the segue object and you can ofcourse pass some data to it by accessing the properties.

What you want to achieve is to pass data to some ViewController which is not even allocated in memory yet. This line in your code:

PinSubmitViewController *pinViewController = [[PinSubmitViewController alloc]init];

will create a new object of PinSubmitViewController which has nothing to do with the pushed segues.

So, you should either pass data to your VerificationViewController and then pass it to PinSubmitViewController or you can use NSUserDefaults to save and access data(as I can see data is not much). You can perhaps use Singletons as well.

OTHER TIPS

You don't need to create a new UIViewController inside prepareForSegue method. The one you create — PinSubmitViewController — gets deallocated at the end of prepareForSegue method, since ARC doesn't see any strong references to it.

In your situation I'd pass data thru VerificationViewController or use NSUserDefaults.

P.S. You also don't need to manually call [self prepareForSegue:segue sender:self] — it gets called automatically in the process of performing segue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top