crash application while delete section from UITableView - objective-c

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?

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.

tableview won't update after adding objects to an array

I have a tableview inside a popover in my main view which is a web browser. Whenever the user visits a web page I want it to add the page to a list of recently visited websites. I have the code set up to add the URL as a string to the array that is the data source for the table view. The table view only shows the first site visited and won't show anything past that. However I know the sites are being added to the array because the array shows the Sites using NSLog statements after being added. However they still won't show up in the table. Can anyone help me?
EDIT:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [recentlyVisitedUrls count];
}
Also make sure you are returning the correct length of your array from – tableView:numberOfRowsInSection:
Try
[tableView reloadTable];
after you add the new data.
If you wan't animated updating, you can call:
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO]
If you need animation, it will be better read: Table View Programming Guide for iOS, you need Batch insert… part.
If you have a large table, [tableView reloadData] is probably not ideal. It'll also will reset your view to the beginning of the table, which may or may not be desirable. You might try something like this:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_model.recordCount - 1 inSection:0];
[_tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
[_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
BTW, _model is the data delegate class for the table in the example.
Also, make sure the data delegate updates it's total count correctly before you insert, or your app will crash on the insertRowsAtIndexPaths.

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.

Add rows to existing UITableView section

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