Selch
Selch

Reputation: 131

Dynamically add rows to multiple sections in grouped table

I've dug through and found several examples of dynamically adding rows to a UITableView just not to a grouped table and I just can't figure this out. I know what I want to do - I have a grouped table with 3 sections. I want to dynamically add an 'Add new item' row/cell to sections 1 and 2 but not 0 when the edit button is selected.

First I'm confused about numberOfRowsInSection. I'm initially loading my table with this.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return [[[tableData objectAtIndex:section] objectForKey:@"Rows"] count];

}

Do I need to add an if statement for when I'm editing to add a row to the count for those sections when I'm editing? such as:

if (editing) {

    return [[[tableData objectAtIndex:section] objectForKey:@"Rows"] count] + 1;
}

And I realize that the above, if correct, would add a row to each section not just 1 and 2. How would I limit that?

Next is my setEditing function. This is where my real problem is. I believe I need to make an array of index paths of the last rows of sections 1 and 2 so that I can insert the new rows below them. The below is wrong, just my experimentation trying to get something inserted somewhere.

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[self.tableView setEditing:editing animated:animated];

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:1];
NSMutableArray* paths = [[NSMutableArray alloc] initWithObjects:indexPath, nil];

NSArray *paths = [NSArray arrayWithObject:
                  [NSIndexPath indexPathForRow:6 inSection:1]];
if (editing) {
    [[self tableView] insertRowsAtIndexPaths:paths 
                            withRowAnimation:UITableViewRowAnimationTop]; }
else {
    [[self tableView] deleteRowsAtIndexPaths:paths 
                            withRowAnimation:UITableViewRowAnimationTop]; }

}

That crappy code returns this error:

Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (5) must be equal to the number of rows contained in that section before the update (5), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted).

So I'm a bit lost. IndexPaths and Arrays are new to me. Actually it's all new to me and I do pour over the docs and posts here but I can't say I always understand it. Any help would be appreciated. I also do realize that I still need to configure my cell and commitEditingStyle methods but I think I can figure that out if I can get a handle on understanding index paths and arrays.

thanks

-----EDIT-----

Ok, so I got this for the most part. I've added a new row to my sections when editing:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section     {

if(self.editing && section != 0) {
    int rows = 0;
    rows = [[[tableData objectAtIndex:section] objectForKey:@"Rows"] count] + 1;
    return rows;
}
else {
    int rows = 0;
    rows = [[[tableData objectAtIndex:section] objectForKey:@"Rows"] count];
    return rows;
    }
}

I've figured out how to apply a label to those new rows when in editing mode:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
static NSString *CellIdentifier= @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
//configure the cell...
if(self.editing && indexPath.section != 0 && (indexPath.row == [[[tableData objectAtIndex:indexPath.section] objectForKey:@"Rows"] count])) {
    cell.textLabel.text = @"Add new Item";
    return cell;
}
else    
    cell.textLabel.text = [[[tableData objectAtIndex:indexPath.section] objectForKey:@"Rows"] objectAtIndex:indexPath.row];
return cell;

And I'm properly setting the last row of my two sections where the row was added to style insert:

-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {

if (indexPath.section == 0)
    //Can't edit the items in the first section
    return UITableViewCellEditingStyleNone;
else
    //if it's the last row in sections 1 or 2 make it an Insert item
    if(self.editing && indexPath.section != 0 && (indexPath.row == [[[tableData objectAtIndex:indexPath.section] objectForKey:@"Rows"] count])) {
        return UITableViewCellEditingStyleInsert;
    }
    //Everything else in sections 1 or 2 should be Delete style
    else
        return UITableViewCellEditingStyleDelete;

}

That all works. Of course it doesn't animate and I still need help with that. I think, but I'm not certain that I need to do the insert/delete rows from the setEditing method. What I believe I need to do is make an array to the sections that I'm editing and then insert the rows there. The *paths array below is wrong because I need an array that points to the last rows in sections 1 & 2 and I don't know how to create that array. Or maybe everything I'm thinking is just wrong. Can someone help point the way? Much thanks.

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[self.tableView setEditing:editing animated:animated];

NSArray *paths = [NSArray arrayWithObject:
                  [NSIndexPath indexPathForRow:?? inSection:??]];
if (editing) {
    [[self tableView] insertRowsAtIndexPaths:paths 
                            withRowAnimation:UITableViewRowAnimationTop]; }
else {
    [[self tableView] deleteRowsAtIndexPaths:paths 
                            withRowAnimation:UITableViewRowAnimationTop]; }

}

Upvotes: 0

Views: 5200

Answers (1)

murat
murat

Reputation: 4963

Do I need to add an if statement for when I'm editing to add a row to the count for those sections when I'm editing?

Yes, in your tableView:numberOfRowsInSection: method, you should return count + 1 in the editing mode. If you do not want to add a row to section 0 then adjust your if condition, i.e. if( self.editing && section != 0)

Your second problem is related to the first one. You are inserting a new row to the section 1 but numberOfRowsInSection still returns 5 for that section. It should return 6.

The methods insertRowsAtIndexPaths:withRowAnimation: and deleteRowsAtIndexPaths:withRowAnimation: are just to reload the table efficiently and with animation. I suggest you to implementsetEditing:animated function as below for now. Then you should implement your tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath: methods by taking editing state into account. After everything is working properly, you can use insert and delete methods to have more control over which parts of the table are reloaded.

- (void)setEditing:(BOOL)editing animated:(BOOL)animated{
     [super setEditing:editing animated:animated];
     [self.tableView reloadData];
}

--EDIT--

You are in the correct path. You can get the indexPaths to delete/insert with a code similar to below:

NSArray *paths = [NSArray arrayWithObjects:
  [NSIndexPath indexPathForRow:[[[tableData objectAtIndex:1] objectForKey:@"Rows"] count] inSection:1],
  [NSIndexPath indexPathForRow:[[[tableData objectAtIndex:2] objectForKey:@"Rows"] count] inSection:2],
  nil
];

Upvotes: 1

Related Questions