Add rows to existing UITableView section - objective-c

I am trying to get some sample code on how I would add rows to an existing UITableView. I am trying to use the insertRowsAtIndexPaths: function.
[tableView insertRowsAtIndexPaths:addindexes withRowAnimation:UITableViewRowAnimationTop];
Any ideas how these indexes work and how I can add to an existing section or, if I don't have a section, then create a new section?

You have to create an array of indexpaths as -
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
for example if you want to insert 2nd row in section 0 and already have 1 row in section 0 then create an index path for row 1 in section 0 and call the insertRowsAtIndexPaths on table view, it will insert 2nd row in section.
If there is no section in table view then you should use an int for data source to give no of sections in table view, in this use -
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return noOfSection; //here section is as int which is initially zero
}
and initially your int "noOfSection" will be zero then there will be no section in table, then when you want to add section increase your int value by 1 and call [tableView reloadData];

You need to handle these functions if you are gonna insert row and section in a table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return noOfSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[noOfRows objectForIndex:section] intValue];
}
also if you are updating your table view it is recommended that you use beginUpdates and endUpdates method.
this is how you insert new row and section.
noOfSections++;
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationTop];
// update your array before calling insertRowsAtIndexPaths: method
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:2]]
withRowAnimation:UITableViewRowAnimationTop];
check the sample code provided by the apple.
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UITableView_Class/Reference/Reference.html

Related

UITableView insert row below tapped cell

I'm extremely confused. I have looked at several posts to try to figuere out how to do this. What i would like to do is detect when a UITableViewCell is tapped and then insert a row right below that row with a menu.
I implemented detecting the tapped item but I can't figure out how to insert the new row right below the row that was just tapped.
Here is the method that handles the tapped cell.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = nil;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Locations *location = nil;
if (self.searchDisplayController.active) {
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
location= [self.searchResults objectAtIndex:indexPath.row];
NSLog(#"location : %#" ,location.locationName);
[self.locations addObject:#"New Entry"];
[tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:YES];
//[self.tableViewForScreen insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
} else {
indexPath = [self.tableView indexPathForSelectedRow];
location = [self.locations objectAtIndex:indexPath.row];
NSLog(#"location : %#" ,location.locationName);
[tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:YES];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// set the tapped item pointer equals to the locations mutable array variable wich essentially is the
// data source of the table view.
//Locations *tappedItem =[self.locations objectAtIndex:indexPath.row];
//access the location name and print to log.
}
Obviously it fails at the part of insert
[tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:YES];
Can someone give me a hand?
The error is the following.
reason: 'Invalid update: invalid number of rows in section 0. The
number of rows contained in an existing section after the update (154)
must be equal to the number of rows contained in that section before
the update (154), plus or minus the number of rows inserted or deleted
from that section (1 inserted, 0 deleted) and plus or minus the number
of rows moved into or out of that section (0 moved in, 0 moved out).'
Here's a post that I looked at.
UITableView action row
http://adcdownload.apple.com//videos/wwdc_2011__sd/session_125__uitableview_changes_tips_tricks.m4v
The problems is that you call insertRowsAtIndexPath: but you don't first update the data source to include the data for the new row.
You seem to do this correctly when selecting a row in the search table but not the main table.
First of all do not use
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
you can take indexPath from method parameters
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
It seems that you have problems because you are calling insertRowsAtIndexPaths but you are not updating data source.

Updating UITableView that is managed by NSFetchedResultsController and has 1 extra cell in the first section

Master Detail Application -
I have a UITableViewController that is managed by an NSFetchedResultsController and its delegate methods. I also have one extra cell in the first section of the tableview that has a UIWebView in it that displays an embedded video. This cell is not part of the NSFetchedResultsController. I add it inside of an IF statement when -tableView cellForRowAtIndexPath is called, that checks to see if it's the first section and first row. Everything works great for the most part. I can select a row and display it in the DetailViewController, I can delete items from the tableView, I can change the information in the DetailViewControllerand the tableViewCell labels update with out any problem.
MY ISSUE
The only time I have an issue with the way it is setup is, when I delete the last object from the first section in the tableView.
THE ERROR
CoreData: error: Serious application error. An exception was caught
from the delegate of NSFetchedResultsController during a call to
-controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section
after the update (3) must be equal to the number of rows contained in
that section before the update (2), plus or minus the number of rows
inserted or deleted from that section (0 inserted, 0 deleted) and plus
or minus the number of rows moved into or out of that section (0 moved
in, 0 moved out). with userInfo (null)
CODE
numberOfRowsInSection
This is where I check to see if the video is available and if the section is 0 return 1 extra row. else return the object count from the NSFetchedResultsController. I'm assuming this is where my issue is. However, I don't know how to fix it. Because I have it managed by the NSFetchedResultsController delegate methods is there any thing I can do inside of the "type" in the switch statement?
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0 && self.videoInfoReceived == YES) {
id <NSFetchedResultsSectionInfo> secInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [secInfo numberOfObjects] + 1;
} else {
id <NSFetchedResultsSectionInfo> secInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [secInfo numberOfObjects];
}
}
NSFetchedResultsController Delegates
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"didChangeSection - ChangeInsert");
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"didChangeSection - ChangeDelete");
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:#[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"didChangeObject - ChangeInsert");
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"didChangeObject - ChangeDelete");
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
NSLog(#"didChangeObject - ChangeUpdate");
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:#[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"didChangeObject - ChangeMove");
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
You need more conditional code to check if any index path you're sent is for the first (zero) section. If it is, the FRC is being given the 'wrong' row number because you have told the table view one row count and the FRC understands a different one.
Basically, everywhere you receive an index path from the table view, check the section, if it == 0, create a new index path with the same section and row - 1 and use that to access the objects in the FRC.
Conversely, when you receive an index path from the FRC you need row + 1 before you can use it to ask the table view to insert/delete/move.
In your question you state:
when I delete the last object from the first section in the tableView
Which would lead me to expect the exception to state the following (emphasis added):
CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)
Because the exception states that the row count is increasing from 2 to 3 without any rows being added, I think that your error is down in the model layer and not in the table view code. Your table view code looks great to me.

crash application while delete section from UITableView

In tableview I have many sections, on the top row of section I have a delete button, I want to do delete section after clicking button but its crashing please help me how can I do this?? here is the code...
//****** adding delete section button
CellButton *_sectionButton = (CellButton*)[cell viewWithTag:10];
_sectionButton.hidden = YES;
_sectionButton.indexPath = indexPath;
[_sectionButton addTarget:self action:#selector(sectionDeleteButton:) forControlEvents:UIControlEventTouchUpInside];
-(void)sectionDeleteButton: (id)sender
{
CellButton *_secbtn = (CellButton*)sender;
NSInteger sectionNumber = _secbtn.indexPath.section;
[self.tableView beginUpdates];
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionNumber] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
[self.tableView reloadData];
}
EDIT: The error messsage is:
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1054 2013-07-04 04:25:15.921 estimation[9025:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (2) must be equal to the number of sections contained in the table view before the update (2), plus or minus the number of sections inserted or deleted (0 inserted, 1 deleted)
I guess the numberOfSectionsInTableView: returns the previous number of sections. You must make sure that what you tell the table view to do also happens in the data source. That is, if you delete a section, then the numberOfSectionsInTableView must also return a number one less than before. The same stands for cells and everything else. This is probably described in the error you get.
You have to manage your number of sections in numberOfSectionsInTableview: delegate method
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//#warning Incomplete method implementation.
// Return the number of rows in the section.
return [MLControl shared].arrBuyList.count;//1;//[MLControl shared].arrBuyList.count;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
// [tableView beginUpdates];
NSLog(#"indexPath.row=%ld,indexPath.se=%ld",(long)indexPath.row,(long)indexPath.section);
[[MLControl shared].arrBuyList removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
// [tableView endUpdates];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
I met this problem, but the reason is different from yours.
When I add a section for the tableView, I reload data with this method, this also crash logging like yours:
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
Why do I use this method to reload my table? If I only refresh cells, this works fine, but I forgot I want to change the sections. For more information: What is More reliable way to reload UITableView Data?

Objective c - Deleting rows of a table view

it's my first question in this awesome site. I've really searched a lot and yet find an answer to the next problem.
I have a table view with 9 cells. One of the cells has a switch button in it. When the switched button value changes, i want to delete 2 rows of the table view. I have written the next code:
- (IBAction)switchValueChanged:(id)sender {
NSLog(#"%#", ([switch isOn]) ? #"ON" : #"OFF");
NSArray *deleteIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:1 inSection:0],
[NSIndexPath indexPathForRow:2 inSection:0],
nil];
UITableView *tableView = (UITableView *)self.view;
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
// I Have to change the number of rows in the section here.
[tableView endUpdates];
}
When i run this, I'm getting a problem relating to the number of rows in the section - this number has been changed so i need to change it. I really can't find how i change it, but i know where i have to change it (see code).
How can i do it? how can i call the method numberOfRowsInSection:NSInteger and set also the rows?
Thank you very much :)
The number of rows in the table is in your
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
You need this to match the new number of rows in the table
---- EDIT
This means that you will need to keep track of the number of rows in your table.
Start with this set to 9 and delete 2 every time you change the switch
- (IBAction)switchValueChanged:(id)sender {
NSLog(#"%#", ([switch isOn]) ? #"ON" : #"OFF");
// We are going to delete 2 rows
numberOfRows -= 2;
...
and in your numberOfRowsInSection instead of returning 9 each time, return the new number of rows
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return numberOfRows;
}
You should delete the data from the datasource not the table cells and then just to refresh the table view. At least this is how i would do the design.
You have to also delete the data from the datasource of the table view. The data source is any container that holds the actual data which is being displayed on the table view. Just deleting the row only deletes the visual item of the row, when tableview is reloaded - it will want to draw 9-2 rows....but since number of rows is still returning 9, it will throw an inconsistency exception and tell you why. See the log carefully.

Duplication in Uitableview cell?

i got tired from trying all night to solve this issue at the begining my issue is when i add a new data it stored the data into NSMutableArray and in the cellForRowAtIndexPath i show the data, because i have sections so what i did was as follow
if(indexPath.section == 0)
{
for (NSDictionary *dictt in data) {
if ([[dictt objectForKey:#"Type"] isEqualToString:#"Electricity"]) {
NSLog(#"%#",[dictt objectForKey:#"Account"]);
cell.textLabel.text = [dictt objectForKey:#"Account"];
cell.detailTextLabel.text = [dictt objectForKey:#"Type"];
[mainTableView reloadInputViews];
}
}
}
When it comes to final result it show this first
when i add another data it show this
and if their is a data in another section let say water and when i delete that it starts deleting from Electricity section
and here is the delete function:
-(void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
[data removeObjectAtIndex:indexPath.row]; [tableView
deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationTop];
[self saveData];
[mainTableView reloadData]; }
You are using the same array for all of your sections, so you definitely want to get a better data structure in place. In your delete function you aren't checking the section of the tableview, so that's why it's deleting from the wrong section.
Basically, you want to create an array that contains arrays of data for each section, so that in your master array the object at index 0 is the array for section 0 etc.