views:

2656

answers:

4

Hi there,

I'm currently building an iPhone app that will display data from an NSMutableArray called "stories". The array structure looks like so (via NSLog):

    2009-07-20 12:38:30.541 testapp[4797:20b] (
    {
    link = "http://www.testing.com";
    message = "testing";
    username = "test";
},
    {
    link = "http://www.testing2.com";
    message = "testing2";
    username = "test2";
} )

My cellForRowAtIndexPath looks like this currently:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];


}

    for (NSDictionary *story in stories) {
     [cell setTextColor:[UIColor whiteColor]];
     [cell setFont: [UIFont systemFontOfSize:11]];
     cell.text = [NSString stringWithFormat:[story objectForKey:@"message"]];
    }
      return cell;
}

Currently my UITableView displays multiple entries of the SAME item (which happens to be the final set in the array). How can I get it to successfully loop through the array and display the next item's message in the cells one after the other.

Thanks in advance :)

Benji

A: 

There is no need to have a loop here - what you want to do is to use the index of the table cell and get the corresponding element of your array (it is unclear, are you using an array or a dictionary?). So, for example, the fourth element of your array would be placed in the fourth table cell.

Here is the fix:

 NSDictionary *story = [stories objectAtIndex: indexPath.row];
cell.text=[NSString stringwithFormat:[story objectForKey@"message];
zPesk
A: 

Your problem here is this

for (NSDictionary *story in stories) {

[cell setTextColor:[UIColor whiteColor]];
[cell setFont: [UIFont systemFontOfSize:11]];
cell.text = [NSString stringWithFormat:[story objectForKey:@"message"]];
}

You are setting your cells to always display the last story, what you want to do it something like

NSDictionary *story = [stories objectAtIndex: indexPath.row];
cell.text=[NSString stringwithFormat:[story objectForKey@"message];
Daniel
A: 

instead of

for (NSDictionary *story in stories) {
    cell.text = [NSString stringWithFormat:[story objectForKey:@"message"]];
}

you want

int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
cell.text = [NSString stringWithFormat:[[stories objectAtIndex: storyIndex] objectForKey:@"message"]];

your cellForRowAtIndexPath method will get called once for each cell, so you only want to set the text for that particular cell.

note that for a simple table with no sections, an "index path" ends up just being an array with one integer in it.

David Maymudes
what's up with the storyIndex int?
Dave DeLong
guilty of copying code from somebody else's bad example back a month ago when I didn't really understand what indexPaths are and apparently the author didn't know about the iPhone-specific "row" and "section" methods....
David Maymudes
+3  A: 

You're misunderstanding how the cellForRowAtIndexPath: method works.

The way you have it, you're creating a single cell, and then repeatedly resetting its text, textColor, and font properties, then returning a single cell.

The key to understanding your issue is understanding that cellForRowAtIndexPath: is called multiple times, once for each cell that will be displayed on the screen. So instead of your for() loop, do this:

NSDictionary * story = [stories objectAtIndex:[indexPath row]];
[cell setTextColor:[UIColor whiteColor]];
[cell setFont: [UIFont systemFontOfSize:11]];
cell.text = [NSString stringWithFormat:[story objectForKey:@"message"]];

The indexPath parameter being passed in is how the tableView indicates which cell it's asking you for. We use that to grab the corresponding story dictionary from your array.

EDIT:

I'd also like to point out that this code is not iPhone OS 3.0 compatible. The 3.0 SDK introduced changes into how UITableViewCell works, including its view hierarchy. You probably want to be accessing the textLabel of the cell, and then setting the properties of that, like this:

NSDictionary * story = [stories objectAtIndex:[indexPath row]];
[[cell textLabel] setTextColor:[UIColor whiteColor]];
[[cell textLabel] setFont: [UIFont systemFontOfSize:11]];
[[cell textLabel] setText:[NSString stringWithFormat:[story objectForKey:@"message"]]];
Dave DeLong
Hi Dave,Thanks for the useful post and 3.0 compatibility point, for some reason it seems to be crashing for me with the error:"*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (2) beyond bounds (2)'"Thanks again.
Benji Barash
@Benji that means that you've only got 2 items in your array, but the tableView is asking for a third. Make sure that you're returning [stories count] in your numberOfRowsInSection delegate method. If you are, then make sure you aren't mutating the NSArray behind the scenes and adding/removing stuff from it without telling the tableview (you tell it by sending it the reloadData message).
Dave DeLong
Dave you're a genius, I hadn't returned [stories count]. Thanks again and have a great day :)
Benji Barash