Hi I am working with the chat app every thing is working fine.Now I need to delete a message.For that i am using long Gesture on tableview.But My Tableview is configured like sections are Dates and messages are Rows.Now when Long Tap on row it is showing Row number not respect to Sections.So I am using below Code it showing the currect index path.Then I am deleting That message in sqlite.But getting error like index Beyond the Exception
CGPoint p = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
id<SOMessage> message = self.conversation[indexPath.section][indexPath.row];
int index = (int)[[self messages] indexOfObject:message];
if (indexPath == nil) {
NSLog(#"long press on table view but not on a row");
} else if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
NSLog(#"long press on table view at row %d", index);
}
in the above code, index is my indexapth value for deleting a row.and how i am deleting row in tableview is
[self.tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationFade];
below is my error log
invalid number of rows in section 1. The number of rows contained in an existing section after the update (10) must be equal to the number of rows contained in that section before the update (10), 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).'
Not getting you question... you are doing every thing right, if you are able to delete row in sqlite with this then you can even in UITableView.
To delete row directly from table view just add following in your code:
else if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
[self.tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationFade];
}
I really didn't get your question but hope this may help :)
Related
I have a custom tableview cell and am getting data from the network 10 at a time. As users scroll down it fetches 10 more and displays the content.
Sometimes, my fetch can be a bit slow (>3-4 secs) and during that instance(when a fetch is currently happening), if my custom tableview cell is clicked (on the visible rows) then the app crashes at the following line. (I followed the example here to expand/collapse my cell and show more content)
Obviously the tableview:reloadRowsAtIndexPaths is called as and when network fetch is done and making changes to tableview data..so how can i fix this issue ?
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"ROW SELECTED..%ld",indexPath.row);
if (self.selectedIndex ==indexPath.row)
{
self.selectedIndex=-1;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
return;
}
if (self.selectedIndex!=-1){
NSIndexPath *prevPath = [NSIndexPath indexPathForRow:self.selectedIndex inSection:0];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:prevPath] withRowAnimation:UITableViewRowAnimationFade];
}
self.selectedIndex=(int)indexPath.row;
//[self.tableView beginUpdates];
//app crashes at this line !!
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
//[self.tableView endUpdates];
}
The exception i am getting is
*** 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 (10) must be equal to the number of rows contained in that section before the update (11), plus or minus the number of rows inserted or deleted from that section (1 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
If self.selectedIndex!=-1 is true, then you are going to ask the tableview to reload twice. I have a few suggestions:
put all those reload calls into dispatch blocks, so you don't issue them directly in a delegate method
aggregate the last two reloads into a single reload by using a mutable array, but again, dispatch to the main queue.
Also, add some logs. What happens if prevPath is out of range - that cell isn't valid any more?
EDIT: your answer is here:
"The number of rows contained in an existing section after the update (10) must be equal to the number of rows contained in that section before the update (11), plus or minus the number of rows inserted or deleted from that section (1 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out)."
Before the update you had 10 items in this section.
After the update you had 11 items in this section
you inserted one and deleted one (this is not shown in your code snippet)
you didn't move any in or out
So you have one more item in your section (told to the tableview in the delegate method) than insertions (net 0) and moves (net 0).
I have a UITableView of custom cells. Each cell has an NSTimer that can be set by the user and started by tapping a button. The timers work except when a new cell is added to the TableView. In the unwind method (coming from creating a new object for a new cell) I have to reload the data in the TableView so that the new cell appears. This however reloads all the cells causing any running timer to restart. Is there a way I can add the cell without restarting the running timers?
EDIT:
I have a ViewController that creates a new object and then back in the FirstViewController.m I have an unwind method that should update the tableView with a row for the new object. Using the reloadData method won't work because it reloads all of the cells. I would like to just add a new cell without reloading the entire tableView.
-(IBAction)unwind:(UIStoryboardSegue *)segue {
ABCAddItemViewController *source = [segue sourceViewController];
ABCItem *item = source.object;
if (item != nil) {
[self.objectArray addObject:item];
[self.tableView reloadData];
}
}
To do this I've tried adding these lines instead of [self.tableView reloadData]:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self.objectArray indexOfObject:item] inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
However, the app crashes and I get this message:
'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) 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 (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).'
The number of rows in the tableView is determined by [self.objectArray count] in the numberOfRowsInSection: method.
It is not a good idea to add timers to cells because they are reused. They are views. My recommendation is to create some objects which have the text / info you want to display in these UITableViewCells and add the timers to those objects. This way the timer info is not stored in the cells and they will store state
There is no need to reload entire table for just inserting one cell. You can add the cell like
self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:row inSection:section]] withRowAnimation:UITableViewRowAnimationLeft];
[self.tableView endUpdates];
When I am reloading one section,after deleting last object from array and reloading section
NSIndexSet *indexSet = [[NSIndexSet alloc]initWithIndex:0];
[_LYTPhotosUICreator.getTableViewInstance reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone];
then I have an exception
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. 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 (4), 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).'
Please let me know where I did wrong.
Invalid update: invalid number of rows in section 1 this means section 1 current number is 0, before is 4, however, you now do update section 0.
Try this way.
[self.tableView beginUpdates];
// remove the objects from data source
// give the according row indexpaths
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
My question is about deleting "invisible" rows in a UITableView. When I say invisible, I mean rows that are not showed on the screen. For example, all the rows that aren't returned by calling the UITableView method - (NSArray *)visibleCells.
I'm asking this because I'm developping an "expandable" UITableView. A little bit like a tree. You can have a table like this :
Menu 1
Menu 1.1
Menu 1.2
Menu 2
Menu 2.1
Menu 2.2
And when you click on "Menu 1" the cells "Menu 1.1" and "Menu 1.2" will either appear or disappear. I do this by simply inserting or deleting cells with an animation.
The problem is, if I have long menus and the user scrolls, if half the rows from "Menu 1", for instance, ar hidden (not visible, not showed on the screen, visible only if you scroll down) and that the user wants to reduce "Menu 1" this will cause my application to crash because I'm trying to delete rows that are not visible.
The actual error message is :
* 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 (11) must be equal to the number of
rows contained in that section before the update (15), 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).'
If I do the exact same manipulation with all the rows visible, no problem with the app and the menu behaves correctly.
On your tableview update calls, you need to update the tableview data source as well as the tableview. You can use UITableView's indexPathsForVisibleRows method to find the positions in which to remove the objects from the source, and update your table.
Thanks to all of you for your answers. What I did is I used "indexPathsForVisibleRows" to get the indexPaths of the rows not displayed on the screen and I simply updated my model and called "reloadData" to update my table. This is not the ideal solution I was expecting but it works.
I still don't understand why "-deleteRowsAtIndexPaths" doesn't work for rows not on the screen but actually really present in the table.
I had a similar problem and here goes my solution. Basically the solution involves on changing the cells height to "hide" them.
I've changed the section header to a custom UIControl to looks like any other cell and implemented the follow method to "hide" the rows outside the selected section:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == _selectedSection) {
// If it is the selected section then the cells are "open"
return 60.0;
} else {
// If is not the selected section then "close" the cells
return 0.0;
}
}
For the custom header I've used the following code:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
CGFloat height = [self tableView:tableView heightForHeaderInSection:section];
// Here you can use whatever you want
CGFloat width = 640.0;
UIControl *view = [[UIControl alloc] initWithFrame:CGRectMake(0.0, 0.0, width, height)];
view.tag = section;
// This code is used by my custom UIControl
//
// to change the style for each state
// view.sectionSelected = (section == _selectedSection);
//
// and to change the title
// view.title = [self tableView:tableView titleForHeaderInSection:section];
// This event is used to "close" or "open" the sections
[view addTarget:self action:#selector(didSelectSectionHeader:) forControlEvents:UIControlEventTouchUpInside];
return view;
}
To be more appealing I've added animations to the following method:
- (void)didSelectSectionHeader:(id)sender
{
if ([sender isKindOfClass:[UIControl class]]) {
// Save the old section index
int oldSelection = _selectedSection;
// Get the new section index
int tag = ((UIControl *)sender).tag;
// Get sections quantity
int numSections = [self numberOfSectionsInTableView:_tableView];
// Check if the user is closing the selected section
if (tag == _selectedSection) {
_selectedSection = -1;
} else {
_selectedSection = tag;
}
// Begin animations
[_tableView beginUpdates];
// Open the new selected section
if (_selectedSection >= 0 && _selectedSection < numSections) {
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:_selectedSection] withRowAnimation:UITableViewRowAnimationAutomatic];
}
// Close the old selected section
if (oldSelection >= 0 && oldSelection < numSections) {
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:oldSelection] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[_tableView endUpdates];
}
}
Im a little bit confused about how to add rows to the table view.
I have an array which gets values added to it regularly. I am trying to update the number of rows everytime a new value is added to the array using these lines of code:
// listOfMembers if a
[[self tableView] beginUpdates]; [tableView numberOfRowsInSection:[listOfMembers count]];
[[self tableView] endUpdates];
[[self tableView] beginUpdates];
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
[[self tableView] endUpdates];
however this does not work to change the number of rows.. may i am misunderstanding how the table updates. I get this 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 (5) must be equal to the number of rows contained in that section before the update (4), 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).'
THe crash is on the line:
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
How should I be updating my table view clearly I am doing this in the wrong way.
Ok so the answer to this problem is to simply call the function reloadData. for example:
[tableViewOutlet reloadData];