Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a row in TableView iOS

Tags:

ios

tableview

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?

like image 317
AlvaroSantisteban Avatar asked May 31 '12 17:05

AlvaroSantisteban


People also ask

How do I add a section in Swift?

To add a section around some cells, start by placing a Section around it, optionally also adding a header and footer. As an example, we could create a row that holds task data for a reminders app, then create a list view that has two sections: one for important tasks and one for less important tasks.

What is TableView in iOS?

Overview. Table views in iOS display rows of vertically scrolling content in a single column. Each row in the table contains one piece of your app's content. For example, the Contacts app displays the name of each contact in a separate row, and the main page of the Settings app displays the available groups of settings ...

Can we use TableView in SwiftUI?

In this blog post, I'll introduce the collection view Table in SwiftUI and explain how to leverage this view on iOS 16 to build a multiplatform app. SwiftUI provides several collection views that you can use to assemble other views into dynamic groupings with complex, built-in behaviors.


2 Answers

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

like image 95
trapper Avatar answered Sep 30 '22 14:09

trapper


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];
}
like image 35
Lorenzo B Avatar answered Sep 30 '22 13:09

Lorenzo B