4

I have a UITableView which I have assigned sections. When using didSelectRowAtIndex with indexPath.row I am not getting the correct value. Let's say I'm in section 2, then it starts the row index at 0 again and therefore I am getting the wrong index.

Can anyone tell me how to fix this? I realize that it is possible to get the section index by indexPath.section but I can't figure out how to use this.

bandDetailViewController.band = [self.programArray objectAtIndex:indexPath.row];

I hope you can help me. Thanks in advance :-)

EDIT:

Sample data. My cells for the table view is loaded from this plist.

<array>
    <dict>
        <key>name</key>
        <string>Alphabeat</string>
        <key>description</key>
        <string>Long description.</string>
        <key>scene</key>
        <string>Store Scene</string>
        <key>date</key>
        <date>2011-02-04T20:09:40Z</date>
        <key>hasDate</key>
        <true/>
        <key>weekDay</key>
        <string>Onsdag</string>
        <key>youtubeVideo</key>
        <string>http://www.youtube.com/watch?v=dB01PTZNpBc</string>
    </dict>
    <dict>
        <key>name</key>
        <string>Anne Linnet</string>
        <key>description</key>
        <string>Long description.</string>
        <key>scene</key>
        <string>Store Scene</string>
        <key>date</key>
        <date>2011-02-04T20:09:40Z</date>
        <key>hasDate</key>
        <true/>
        <key>weekDay</key>
        <string>Onsdag</string>
        <key>youtubeVideo</key>
        <string>http://www.youtube.com/watch?v=jWMSqS7fL9k</string>
    </dict>
</array>
PeeHaa
  • 71,436
  • 58
  • 190
  • 262
simonbs
  • 7,932
  • 13
  • 69
  • 115

7 Answers7

8

I just came across this issue as well. I found a simple solution using the section number as you mentioned The following code uses segues to navigate to new controlView from two different sections with two different rows. VERY simple solution!

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


if (indexPath.section == 0)
{


    switch(indexPath.row) {
        case 0:
            [self performSegueWithIdentifier:@"Mission" sender:self];
            break;
        case 1:
            //[self performSegueWithIdentifier:@"Music" sender:self];
            break;

     }
}else{

    switch(indexPath.row) {
        case 0:
            [self performSegueWithIdentifier:@"Contact" sender:self];
            break;
        case 1:
            //[self performSegueWithIdentifier:@"Home" sender:self];
            break;
    }


}

}
codercat
  • 22,873
  • 9
  • 61
  • 85
DCorrigan
  • 646
  • 1
  • 8
  • 18
5

The rows are not consecutive and start from scratch in each section:

section 0:
row 0
row 1
row 2
row ...

section 1:
row 0
row 1
row 2
row ...

...

The best way is to build an NSMutableArray sections with NSMutableArrays for the rows. Than you code gets very easy:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return cellSections.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    CellSection *cellSection = [cellSections objectAtIndex:section];
    return cellSection.cellElements.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellIdentifier = [NSString stringWithFormat:@"Cell-%i-%i", indexPath.section, indexPath.row];

    CellSection *cellSection = [cellSections objectAtIndex:indexPath.section];
    CellElement *cellElement = [cellSection.cellElements objectAtIndex:indexPath.row];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];

        [cell.contentView addSubview:cellElement.contentView];

    }


    return cell;

}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    CellSection *cellSection = [cellSections objectAtIndex:indexPath.section];
    CellElement *cellElement = [cellSection.cellElements objectAtIndex:indexPath.row];

}

EDIT:

Just an example:

@interface CellSection : NSObject {

}

@property (nonatomic, retain) NSMutableArray *cellElements;
@property (nonatomic, retain) NSString *headerString;
@property (nonatomic, retain) UIView *headerView;

@end

@interface CellElement : NSObject {

}

@property (nonatomic, retain) UIView *contentView;
@property BOOL isSelectable;
@property BOOL hasAccessoryIndicator;
@property SEL action;

@end
Manni
  • 11,108
  • 15
  • 49
  • 67
  • I get the idea but I'm afraid that I do not get the code. I have an array called `programArrayIndex` which contains my sections. Then I have an array called `programArray` which contains my cells. I use `NSPredicate` on `programArray` to filter what entries I want to show in the cell. This predicate is stored as `weekDays`. So now I have `programArrayIndex` containing the header and `weekDays` containing each cell I want to show. Now, what would I wanna do to these? – simonbs Feb 07 '11 at 17:46
  • Hmmm, I'm afraid that it would be best that you reorganize your arrays. Don't use two separate arrays for sections and rows. Make an array with your sections and inside this array, every section has an own array with the rows. You'll see that's very comfortable :-) – Manni Feb 07 '11 at 17:59
  • Would you mind giving an example on this? Now I have cleaned up my code to just contain the `programArray` which is my data loaded from a plist. The plist is loaded `NSString *path = [[NSBundle mainBundle] pathForResource:@"Bands" ofType:@"plist"];` and assigned to a temporary array `NSMutableArray* tmpArray = [[NSMutableArray alloc] initWithContentsOfFile:path];` and then `programArray` is "inheriting" the temporary array `self.programArray = tmpArray;` So now I would want to put the entries in `programArray` with a `weekDay` of "Saturday" under the entry "Saturday" in an array, right? – simonbs Feb 07 '11 at 18:41
  • I edit my answer and gives you an example of my CellSection and CellElement. The CellSection contains an NSMutableArray with the rows (=CellElement). – Manni Feb 07 '11 at 18:52
  • Thank you very much for your help. I ended up saving my sections as dictionaries in a dictionary. And under every section I stored my rows as dictionaries. You have been a great help! – simonbs Feb 08 '11 at 18:36
4

I have had the same problem and I have solved it this way:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selected = [_products objectAtIndex:[self getRealIndexFromIndexPath:indexPath]];
NSLog(@"%@", selected);

}

- (NSUInteger)getRealIndexFromIndexPath:(NSIndexPath*)indexPath {   
NSUInteger temp = 0;
for (int i = 0; i < indexPath.section ; i++) {
    temp += [_mySectionedTable numberOfRowsInSection:i];
}
return temp + indexPath.row;

}

Hope it helps :-) Cheers!

Goblin
  • 63
  • 4
1

If I follow you correctly, you could try

NSUInteger index = indexPath.row * (indexPath.section + 1);
bandDetailViewController.band = [self.programArray objectAtIndex:index];

Or something like that. More typically you'll have an array of objects that represent your sections, and each of those section objects will have its own array representing its rows.

Nick Curran
  • 466
  • 3
  • 11
1

If you implemented

tableview cellForRowAtIndexPath

then in the didSelectRowAtIndexPath you can call this method to retrieve the value selected. No need to rearrange your data structures if it is too hard. Its what I ended up doing with the variable length sections and works great.

NSString *selectedValue = [self tableView:theTableView cellForRowAtIndexPath:indexPath].textLabel.text;

casey
  • 1,118
  • 1
  • 13
  • 25
0

The usual approach to dealing with variable-length sections (which I'm assuming is the case here) is to create a collection that represents the sections containing nested collections to represent the rows. So for example you could have a top-level NSMutableArray of section values, where each element is an NSMutableArray of row values.

EDIT

Given the current structure of your plist data, another approach would be to filter the array using an instance of NSPredicate. For example, the following code would filter the rows for the current section based on days of the week:

static NSArray *days;

if (days == nil)
{
    // Populate the array with days of the week in the order 
    // in which you want the table view to present the sections.
    days = [NSArray arrayWithObjects:@"Monday", @"Tuesday", nil];
}

NSString *day = [days objectAtIndex:[indexPath section]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"weekDay like %@", day];
NSArray *filteredDicts = [[self programArray] filteredArrayUsingPredicate:predicate];

Note that you'd also need to modify tableView:numberOfRowsInSection: to use the same mechanism so that it would return the correct number of rows for each section.

jlehr
  • 15,557
  • 5
  • 43
  • 45
  • Would you mind giving an example of this? I understand the idea and it seems very logical I just don't get how it should be written. How can I put my directories (from the plist) into an array in the array? Say, an array (array `weekDays`) contains the days of the week and then I must put the directories from the plist which matches the given date into the right entry in `weekDays`. So all directories where `dayOfWeek = Saturday` goes under `Saturday` in array `weekDays`. I blieve that is what you mean, I just don't get how it should be done. – simonbs Feb 07 '11 at 20:49
  • Without having any idea of what your data looks like, it's impossible to say. Can you provide some sample data, or at least describe what the sections and rows represent in your tableView? – jlehr Feb 07 '11 at 21:50
  • I have updated my original post to show some sampla data. The sections are days in the week and the cells are bands who play that day (the application is for a festival) Say The Beatles and Queen would come to the festival. The Beatles would play Thursday and Queen would play Saturday. Then they would be listed in section "Thursday" and "Saturday". – simonbs Feb 08 '11 at 06:09
  • Thank you very much for your help. I ended up saving my sections as dictionaries in a dictionary. And under every section I stored my rows as dictionaries. You have been a great help! – simonbs Feb 08 '11 at 18:36
-4

If you look at the NSIndexPath documentation, you can see how the NSIndexPath data structure is laid out.

To get the section number you want to do something like:

[indexPath indexAtPosition:0]

To get the row within that section:

[indexPath indexAtPosition:1]
Chris
  • 366
  • 3
  • 11
  • 1
    The question was about iOS, which adds `row` and `section` properties to `NSIndexPath` in a category. The OP's question wasn't about how to access these values, but about how to use them to access the correct element of the corresponding collection. – jlehr Feb 07 '11 at 16:30
  • The asker is talking about NSIndexPath on iOS, not MacOSX. Edit your answer to address that context. – Brandon Feb 07 '11 at 16:34