Adding a row in TableView iOS

16,126

Solution 1

You need to keep the count returned by tableView:numberOfRowsInSection: in sync!

So when you have 30 rows and then tell the tableview to insert a new row you need to make sure tableView:numberOfRowsInSection: will now return 31.

- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
{
   return self.rowCount;
}

- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
   self.rowCount++;

   [self.tableView beginUpdates];
   [self.tableView insertRowsAtIndexPaths:(NSArray *) paths withRowAnimation:UITableViewRowAnimationNone];
   [self.tableView endUpdates];
}

In practice you would probably use an array to track your rows return [self.rows count]; etc

Solution 2

The answer is quite simple. When you want to modify a table view you need to perform two simple steps:

  1. Deal with the model
  2. Deal with table animation

You already perform the second step. But you have missed the first one. Usually when you deal with a table you pass it a data source. In other words some data to display within it.

A simple example is using a NSMutableArray (it's dynamic as the name suggests) that contains dummy data.

For example, create a property like the following in .h

@property (nonatomic, strong) NSMutableArray* myDataSource;

and in .m synthesize it as:

@synthesize myDataSource;

Now, you can alloc-init that array and populate it as the following (for example in viewDidLoad method of your controller).

self.myDataSource = [[NSMutableArray alloc] init];
[self.myDataSource addObject:@"First"];
[self.myDataSource addObject:@"Second"];

Then, instead of hardcoding the number of rows you will display (30 in your case), you can do the following:

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

   return [self.myDataSource count];
}

Now, in you didSelectRowAtIndexPath delegate you can add a third element.

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

   [self.myDataSource addObject:@"Third"];

   [[self tableView] beginUpdates];
   [self.tableView insertRowsAtIndexPaths:(NSArray *) paths withRowAnimation:UITableViewRowAnimationNone];
   [[self tableView] endUpdates];
}

Solution 3

It looks like one big problem is with tableView:numberOfRowsInSection:. You need to return the correct number of rows in that method.

To do that, it's usually best to maintain an NSArray or NSMutableArray of items for the table view so in that function, you can say: return [arrayOfValues count];. Keep the array as a property of your view controller class so that it's readily accessible in all methods.

The array can also be used in cellForRowAtIndexPath:. If you have an array of NSString, you can say cell.text = [arrayOfValues objectAtRow:indexPath.row];.

Then, when you want to add an item to the table view, you can just add it to the array and reload the table, e.g. [tableView reloadData];.

Try implementing this concept and let me know how it goes.

Share:
16,126
AlvaroSantisteban
Author by

AlvaroSantisteban

Updated on June 25, 2022

Comments

  • AlvaroSantisteban
    AlvaroSantisteban about 2 years

    I´m quite new to iOS development and I´m having a terrible time by trying something that should be easy; to add an extra row in a TableView everytime the user clicks on one of the existing rows. There is no real purpose on that action, I´m just wanting to understand the behaviour of TableView.

    So I did the following:

    I used a Split View-based template and changed the number of rows to 30 in the RootViewController.

    - (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
       // Return the number of rows in the section.
       return 30;
    }
    

    The method tableView:didSelectRowAtIndexPath looks in the following manner:

    - (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        /*
        When a row is selected, set the detail view controller's detail item to the item associated with the selected row.
        */
       NSMutableArray* paths = [[NSMutableArray alloc] init];
       NSIndexPath *indice = [NSIndexPath indexPathForRow:30 inSection:0];
       [paths addObject:indice];
       detailViewController.detailItem = [NSString stringWithFormat:@"Second Story Element %d with all its information and bla bla bla", indexPath.row];
       [[self tableView] beginUpdates];
       [self.tableView insertRowsAtIndexPaths:(NSArray *) paths withRowAnimation:UITableViewRowAnimationNone];
       [[self tableView] endUpdates];
    }
    

    When I execute the program and click on one of the elements, I receive the following error:

    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (30) must be equal to the number of rows contained in that section before the update (30), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted).'

    I did not change any other part of the code that the template provides.

    I read quite extensively the documentation from Apple and the responses to the following questions: Add a row dynamically in TableView of iphone and how to properly use insertRowsAtIndexPaths?

    The second question seems to address the same problem, but I´m not capable to understand what is happening. What do they mean with dataSource? The response that I understand better says the following:

    It's a two step process: First update your data source so numberOfRowsInSection and cellForRowAtIndexPath will return the correct values for your post-insert data. You must do this before you insert or delete rows or you will see the "invalid number of rows" error that you're getting.

    What does this update of the data source implies?

    Sample code would be HIGHLY appreciated, because I´m totally frustrated.

    By the way, all that I´m trying has nothing to do with entering the editing mode, has it?