27

Trying to do something I've seen documented in a lot of places, but can't seem to manage. I'm trying to pass data from one view to another during a segue.

Here's the prepareForSegue method in the source view:

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

    //pass values
DetailViewController *dest = (DetailViewController *)[segue destinationViewController];

dest.locTitle = [value valueForKeyPath:@"title"];
dest.locInfo = [value valueForKeyPath:@"info"];



// NSLog(@"The title is: %@, and the info is: %@.",dest.locTitle,dest.locInfo);

}

If I enable that last NSLog, I see the correct values...

Here's the interface on the destination view:

#import <UIKit/UIKit.h>

@interface DetailViewController : UIViewController{

}

@property (strong, nonatomic) NSString *locTitle;
@property (strong, nonatomic) NSString *locInfo;
@property (weak, nonatomic) IBOutlet UILabel *detailMainText;
@property (weak, nonatomic) IBOutlet UILabel *detailTitle;

@end

... and here's the viewDidLoad and relevant @synthesize on the destination view:

@synthesize detailMainText,detailTitle,locTitle,locInfo;

- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"In viewDidLoad - the title is: %@ and the info is: %@",self.locTitle,self.locInfo);
detailTitle.text = locTitle;
detailMainText.text = locInfo;
}

That NSLog reports null values for each of those variables.

I'd appreciate any help you could give me. I'm sure I'm doing something stupid, and obvious.

Thanks in advance for your help.


Much later...


OK... I think I'm narrowing it down.

I've discovered that (counterintuitively)

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

gets called after

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

Which is confusing, and also hosed my little scheme to figure out what chunk of my NSDictionary datasource should be displayed in my detail view. Currently I'm doing this:

// send info to detail view according to which row selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    //Get the selected object in order to fill out the detail view
    myValue = [myLocations objectForKey:[locationsIndex objectAtIndex:indexPath.row]];

}

But since this happens after the segue, it's kinda useless. How can I access the row number in the prepareForSegue method?

Thanks again.


... and finally...


Here's the answer to the question:

How do I access a selected row number while in the prepareForSegue method?

Hopefully someone will find it useful.

First, set up a IBOutlet for the tableview in the listView controller's interface:

@property (weak, nonatomic) IBOutlet UITableView *tableView;

Then your prepareForSegue can do this:

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString: @"showDetail"]) {
    //pass values
    NSLog(@"The sender is %@",sender);

    NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
    //Get the selected object in order to fill out the detail view
    id myValue = [myLocations objectForKey:[locationsIndex objectAtIndex:indexPath.row]];

    DetailViewController *dest = [segue destinationViewController];
    dest.locTitle = [myValue valueForKeyPath:@"title"];
    dest.locInfo = [myValue valueForKeyPath:@"info"];

    //NSLog(@"The title is: %@, and the info is: %@.",dest.locTitle,dest.locInfo);
}
}
Daniel
  • 23,129
  • 12
  • 109
  • 154
james Burns
  • 864
  • 2
  • 9
  • 22
  • Do you have anything earlier in the life cycle than viewDidLoad - loadView, initWithCoder, etc? Are your logs from the prepare for segue coming out before the viewDidLoad ones (e.g. It's not that your view has already loaded?) what do you see in view will appear for the string properties? – jrturton Mar 28 '12 at 13:56
  • No. I think I may be closer now, but I'm suffering from the "nested push animation can result in corrupted navigation bar" problem. – james Burns Mar 28 '12 at 14:12
  • I'm using storyboards in xCode 4.2 (Snow Leopard). I have a Navigation Controller, connected wo=ith a RootView relationship to my list controller. My list controller is using - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath to call [self performSegueWithIdentifier:@"showDetail" sender:self]; The storyboard has a push segue from the prototype table cell to the detail view, with an identifier named "show Detail" - is there something wonky in that chain? – james Burns Mar 28 '12 at 14:12
  • 4
    Yes, perhaps! If you have a segue from the cell, you don't need to "manually" call it also from didSelectRow. you're probably getting two segues called, and it is getting confused. Remove your code from didSelectRow - the segue is still performed? – jrturton Mar 28 '12 at 14:16
  • You'd manually perform a segue if the segue went from one viewcontroller object to the next. If you have it coming from a UI element, then it is performed automatically when you tap the element. – jrturton Mar 28 '12 at 14:17
  • You're a friggin' genius. That fixed the "nested" problem. Now I just have problems with the values being passed "late." That is - The segue fires, the view is displayed with the UILabels filled with nil, but if I use the navigation back to the list and then tap on a list item again, I find that the UILabels had been filled with the last values I had clicked on (from the first segue). Something must be wrong with when I'm trying to pass them. Tried viewDidLoad and ViewWillAppear. Same behavior. – james Burns Mar 28 '12 at 14:24
  • Please take a look at my edited question, above. – james Burns Mar 28 '12 at 15:18
  • Hah, well done. If I'd been around I'd have suggested that. You should post this as an answer and accept it once you are allowed (I can't remember what the time limit is, 24 hours or something?) – jrturton Mar 28 '12 at 18:51
  • Just Follow this post.Hope it will helpful http://stackoverflow.com/questions/7937035/how-pass-data-in-seque-ios5-storyboard-uitableview-to-detail-view/24868433#24868433 – Tunvir Rahman Tusher Jul 26 '14 at 07:03

5 Answers5

11

you can achieve it by doing this: first pass the value you want to send to the destination controller here:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     [self performSegueWithIdentifier:@"segueToLocation" sender:the object you want to pass];
}

then get the object here

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString: @"segueToLocation"]) {    
         DetailViewController *dest = (DetailViewController *)[segue destinationViewController];
         //the sender is what you pass into the previous method
         dest.target=sender
    }
}
ltebean
  • 111
  • 1
  • 4
4

You don't need to create a local instance variable of the destination view controller. This will do the same:

[segue.destinationViewController setLocTitle: [myValue valueForKeyPath:@"title"];
[segue.destinationViewController setLocInfo: [myValue valueForKeyPath:@"info"];
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Unsure1
  • 101
  • 6
1

Another option - could use the following method:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath

which fires before prepareForSegue.

Community
  • 1
  • 1
resedasue
  • 434
  • 5
  • 14
1

You can try this:

[[NSString alloc] initWithFormat:@"%@",
  [segue.destinationViewController setLocTitle: [myValue valueForKeyPath:@"title"]];
[[NSString alloc] initWithFormat:@"%@",
  [segue.destinationViewController setLocTitle: [myValue valueForKeyPath:@"info"]];
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Sunil_Vaishnav
  • 425
  • 1
  • 5
  • 15
1

I think I had absolutely the same problem, so hope my solution will help you too. It should answer first part of your question, or at least will help some one else.

First of all you can't assign passed values to properties with viewDidLoad method in the SecondViewController. Doing so, gives nil, as viewDidLoad is implemented before Segue.

And I wouldn't recommend to use viewDidAppear, as as the values will be changed after the view is loaded, witch makes the change process be visually visible.

So, the best option is to assign the values directly to the IBOutlet's. If you want to pass an array of strings, you can assign one array value witch you want to load first, and also pass all NSArray. This will allow your view to be loaded with the value already, and also you will have other values to work with.

You could also call method and pass data.

Jonauz
  • 4,133
  • 1
  • 28
  • 22