I have a UITableView and a scheduler running in the background deleting records from the underlying data object.
Every time an object is deleted I want the table view to update accordingly.
But i keep getting this annoying error message when trying to delete a row from the table view.
* Terminating app due to uncaught exception NSInternalInconsistencyException, reason: "Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible."
The code:
NSIndexPath *indexPath = [NSIndexPath indexPathWithIndex:0];
NSUInteger row = [indexPath row];
NSMutableArray* files = [[NSMutableArray alloc] initWithArray:fileNames];
[files removeObjectAtIndex:[indexPath row]];
[fileNames dealloc];
fileNames = [NSArray arrayWithArray:files];
//[self.fileNames removeObjectAtIndex:row];
[self.tableDraft deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
PS:
I have also tried [tableView reloadData]; but that has undesired side effects, erasing the selected index.
Have you considered following the message's advice? Your index path does not contain both a row and a section component. Use +[NSIndexPath indexPathForRow:inSection:] to create the index path object, so that it has the information the table view requires:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
You need to use this:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex
inSection:sectionIndex];
Use like this
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:sender.tag-1 inSection:0];
CGRect rectOfCellInTableView = [objTableView rectForRowAtIndexPath:indexPath];
CGRect rectOfCellInSuperview = [objTableView convertRect:rectOfCellInTableView toView:[objTableView superview]];
Related
I've encountered a very odd bug. The view in question is a UITableView, where each cell contains a UISwitch as its accessoryView. I have it wired up so that a change in value triggers - (IBAction)toggleEnabled:(UISwitch *)theSwitch, which looks like this:
- (IBAction)toggleEnabled:(UISwitch *)theSwitch
{
UITableViewCell *cell = (UITableViewCell *)theSwitch.superview.superview;
NSIndexPath *indexPath = [(UITableView *)self.tableView indexPathForCell:cell];
Alarm *alarm = [self.fetchedResultsController objectAtIndexPath:indexPath];
alarm.unrelatedProperty = #"This property is unrelated to the switch.";
}
The buggy behavior is that the switch immediately reverts back to its original state. As soon as you flick it, it flicks right back. I did a little more testing, changing my code to this:
- (IBAction)toggleEnabled:(UISwitch *)theSwitch
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
Alarm *alarm = [self.fetchedResultsController objectAtIndexPath:indexPath];
alarm.unrelatedProperty = #"This property is unrelated to the switch.";
}
Now, the reverting behavior only occurs on the very first switch in the list (at row 0). All the other switches work fine, which leads me to believe that it's something to do with modifying an object at a given indexPath. The switches work fine with this code, so I'm pretty sure it's due to the assignment:
- (IBAction)toggleEnabled:(UISwitch *)theSwitch
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
Alarm *alarm = [self.fetchedResultsController objectAtIndexPath:indexPath];
}
Anyone know what could be happening? Thanks!
I have the following code
[self.tV beginUpdates];
NSIndexPath *iP = [NSIndexPath indexPathForRow:indexArray.count inSection:0];
[indexArray addObject:iP];
[self.tV insertRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
[self.tV endUpdates];
I get 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 (2) 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 (2 inserted, 0 deleted) and plus or minus the number of rows moved into
or out of that section (0 moved in, 0 moved out).'
I'm not sure where the 2 inserted is coming from. This code is called every time I click a button. The first time there is one element in indexArray, as seen in the code I add one more element but it seems as if it is trying to add both elements again. Is that correct?
UPDATE
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
if(_imgList.count>0)
{
NSMutableString *fileName = [[NSMutableString alloc]
initWithString:[NSString stringWithFormat: #"img"]];
[fileName appendString: [_imgList objectAtIndex: _resultTag]];
UIImage *image = [UIImage imageNamed: fileName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(_xPos, 0, image.size.width, image.size.height);
[cell addSubview: imageView];
_xPos += SPACING;
}
return cell;
}
- (IBAction)btn:(UIButton *)sender {
[self.resultList beginUpdates];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:indexArray.count inSection:0];
[indexArray addObject:indexPath];
[self.resultList insertRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
[self.resultList endUpdates];
}
The issue is that you aren't changing the size of _imgList (from which, I assume, is derived the return value of the tableView:numberOfRowsInSection: method, but you don't show this method). By inserting a row in the table view, but not updating the data source to reflect that new row, you have created an inconsistency in your application.
To ensure that this doesn't happen, make the changes to your data source that reflect exactly the changes you are making to the rows, and do so before inserting or deleting any rows.
You don't show code that declares or instantiates _imgList so if it's not an NSMutableArray you'll need to make it one, and use methods like addObject:, insertObject:atIndex:, and removeObjectAtIndex: to insert and remove the appropriate objects. In your case, your code would become something like this:
NSInteger indexToAdd = _imgList.count;
[_imgList addObject:#"whatever"];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:indexToAdd
inSection:0];
[self.resultList insertRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
.h
int insertRow;
.m
- (void)viewDidLoad
{
self.insertRow = self.YourArr.count;
}
[self.tV beginUpdates];
NSIndexPath *iP = [NSIndexPath indexPathForRow:self.insertRow inSection:0];
[indexArray addObject:iP];
[self.tV insertRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
[self.tV endUpdates];
self.insertRow = self.insertRow + 1;
It may be solve your problem :)
I have a UITableView. I'm population it from a NSDictionary with arrays for each set of items on the table: labels, footers, Headers, UIViews, etc.
In section 0, I want a row #2 appear when a switch in row #1 is switched to on.
What I have done and it works is, in numberOfRowsInSection I added this code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (interruptor.isOn==NO && section==0) {
return [[[infoTableContentArray objectAtIndex: section] objectForKey:kLabelKey] count]-1;
}else{
return [[[infoTableContentArray objectAtIndex: section] objectForKey:kLabelKey] count];
}
}
and the action linked to the switch (interruptor) is:
-(IBAction)accioInterruptor:(id)sender{
[infoAndSettingsTable reloadData];
}
so when the switch is switched, the table reloads and the cell appears or disappears.
it actually works, but there is no animation, which makes it, mhh... well, you know.
I've tried to implement the reloadRowsAtIndexPaths:withRowAnimation, adding it to the code called by the switch:
-(IBAction)accioInterruptor:(id)sender{
[infoAndSettingsTable beginUpdates];
[infoAndSettingsTable reloadRowsAtIndexPaths:[[infoTableContentArray objectAtIndex: 0] objectForKey:kLabelKey] withRowAnimation:UITableViewRowAnimationBottom];
[infoAndSettingsTable endUpdates];
}
But, it dowsn't work. It crashed on the line [infoAndSettingsTable endsUpdates];
BTW, in all the cases the following:
[[infoTableContentArray objectAtIndex: 0]
is the array which contains the labels for that section.
Am I doing it right or I'm Epic-Failing alltogether?
Thanks in advance!
simple way to do this......
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
insertIndexPaths is an array of NSIndexPaths to be inserted to your table.
deleteIndexPaths is a array of NSIndexPaths to be deleted from your table.
Example array format for index paths :
NSArray *insertIndexPaths = [[NSArray alloc] initWithObjects:
[NSIndexPath indexPathForRow:0 inSection:0],
[NSIndexPath indexPathForRow:1 inSection:0],
[NSIndexPath indexPathForRow:2 inSection:0],
nil];
got it from this question
the argument to reloadRowsAtIndexPaths: should be an array of NSIndexPath objects identifying the rows you want to reload, not the labels for that section. Also, looks like you want to reload a section so I would try the following:
-(IBAction)accioInterruptor:(id)sender {
[self reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationBottom];
}
Why don't you just use UITableView's insertRowsAtIndexPaths:withRowAnimation:? It has been built exactly for this purpose, the UITableView class reference has the exact description and usage examples.
Apart from being cleaner it is also more performant since you don't have to reload the entire table (only really matters if you have lots of cells in it though)
I have a UITableView. I want to update the table data based on selection made. Right now I use [mytable reloadData]; I want to know if there is any way where I can just update the particular cell which is selected. Can I modify by using NSIndexPath or others? Any suggestions?
Thanks.
For iOS 3.0 and above, you just have to call :
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
To reload row 3 of section 2 and row 4 of section 3 for example, you'll have to do this :
// Build the two index paths
NSIndexPath* indexPath1 = [NSIndexPath indexPathForRow:3 inSection:2];
NSIndexPath* indexPath2 = [NSIndexPath indexPathForRow:4 inSection:3];
// Add them in an index path array
NSArray* indexArray = [NSArray arrayWithObjects:indexPath1, indexPath2, nil];
// Launch reload for the two index path
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
You can also get a reference to the UITableViewCell object and change its labels, etc.
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = #"Hey, I've changed!";
I think you're looking for this method of UITableView:
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
Im trying to highlight the first row in my table upon first loading the data and just cannot get it to work!
I have tried lots of ways with no joy, the latest attempt being this:
NSUInteger indexArr[] = {0,1};
NSIndexPath *n = [NSIndexPath indexPathWithIndexes:indexArr length:2];
[self.tableView scrollToRowAtIndexPath:n atScrollPosition:UITableViewScrollPositionTop animated:NO];
try
[self.tableView selectRowAtIndexPath:n animated:YES scrollPosition:UITableViewScrollPositionTop];
you should probably do this after your view has appeared.