简体   繁体   中英

Passing data between two controllers using storyboards

I am trying to pass data from one UITableViewController to another. This is my code in the initial view controller:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Subject *subject = (Subject *)[self.fetchedResultsController objectAtIndexPath:indexPath];
[self showList:subject animated:YES];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (void)showList:(Subject *)subject animated:(BOOL)animated {
ListsViewController *lists = [[ListsViewController alloc] initWithStyle:UITableViewStyleGrouped];
lists.subject = subject;
NSLog(@"%@", lists.subject);

[self performSegueWithIdentifier:@"showDetail" sender:self];
}

The log output was showing that it had the data I wanted had been passed over. However when I perform the segue and log the subject in the ListsViewController is shows null.

Any ideas?

You need to overwrite prepareForSegue:sender: method. The quick fix would be

- (void)showList:(Subject *)subject animated:(BOOL)animated
{
     [self performSegueWithIdentifier:@"showDetail" sender:subject];
}

...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"showDetail"]) {
        ListsViewController *controller = ([segue.destinationViewController isKindOfClass:[ListsViewController class]]) ? segue.destinationViewController : nil;
        controller.subject = ([sender isKindOfClass:[Subject class]]) ? subject : nil;
    }
}

The reason why your code did not work is that in your showList:animated: method you created a ListsViewController instance and assigned it a subject , but this view controller was never presented. Instead performSegueWithIdentifier:sender creates another instance of your ListsViewController class which knows nothing about your subject . That's why you need to wait for UIStoryboardSegue to instantiate a destination view controller from the storyboard and then configure it the way you want, which you can do in prepareForSegue:sender: method.

Also it might be not the best idea to use subject as a sender in performSegueWithIdentifier:sender method, because it's just not the sender :). What I would do is create a property subject in your view controller class and use it prepareForSegue:sender:

@interface MyViewController ()

@property (strong, nonatomic) Subject *subject;

@end


@implementation MyViewController

- (void)showList:(Subject *)subject animated:(BOOL)animated
{
    self.subject = subject;
    [self performSegueWithIdentifier:@"showDetail" sender:self];
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"showDetail"]) {
        ListsViewController *controller = ([segue.destinationViewController isKindOfClass:[ListsViewController class]]) ? segue.destinationViewController : nil;
        controller.subject = self.subject;
    }
}

...
@end

Implement prepareForSegue and pass date in this methos

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([seque.identifier isEqualToString:@"showDetail"])
{
ListsViewController *lists = seque.destinationViewController;
lists.subject = subject;
}
}

That's good, but now you need to add this:

First instead of:

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

You need to send the object:

[self performSegueWithIdentifier:@"showDetail" sender:subject];

Add a property in your ListsViewController.h:

@property (nonatomic, strong) Subject * subjectSegue;

And now in your first view controller:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"showDetail"]) {
        ListsViewController * lists = (ListsViewController *)[segue destinationViewController];
        lists.subjectSegue = sender;
}

You need to understand that performSegueWithIdentifier:sender: creates a new instance of view controller. So the ListsViewController that you have created is not the being displayed on the screen.

You need to override `prepareForSegue:sender:

- (void)showList:(Subject *)subject animated:(BOOL)animated 
{
  [self performSegueWithIdentifier:@"showDetail" sender:self];
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"showDetail"]) {
        ListsViewController *controller = (ListsViewController *)segue.destinationViewController;
    controller.subject = self.subject;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM