I am facing a problem about expandable tableviewcell. It crashes when i try to expand tableviewcell.
I don't understand where app crashes. Please suggest me some solution.
Please Help Me.
My Code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (appDelegate.array_proj == (id)[NSNull null])
return 0;
else
return [appDelegate.array_proj count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([expandedSections containsIndex:section])
{
if ([appDelegate.array_task count]==0)
{
return 0;
}
else
{
NSLog(#"array task count: %d",[appDelegate.array_task count]);
return [appDelegate.array_task count];
}
}
return 1;
}
- (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];
}
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor colorWithRed:53.0/255 green:53.0/255 blue:53.0/255 alpha:1.0];
UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:CGRectZero];
cell.backgroundView = backgroundView;
backgroundView.image = [UIImage imageNamed:#"prjctcell_bg.png"];
if (!indexPath.row)
{
objePro = [appDelegate.array_proj objectAtIndex:indexPath.section];
cell.textLabel.text = objePro.projctname;
appDelegate.intForPid=objePro.pojctid;
if ([expandedSections containsIndex:indexPath.section])
{
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor blackColor] type:DTCustomColoredAccessoryTypeUp];
}
else
{
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor blackColor] type:DTCustomColoredAccessoryTypeDown];
}
}
else
{
if (appDelegate.array_task != (id)[NSNull null])
{
objePro = [appDelegate.array_proj objectAtIndex:appDelegate.storeAppDelegateIndex];
objeTask = [appDelegate.array_task objectAtIndex:indexPath.section];
cell.textLabel.text = objeTask.taskname;
cell.backgroundView = nil;
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
return YES;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
objePro = [appDelegate.array_proj objectAtIndex:indexPath.section];
appDelegate.intForPid=objePro.pojctid;
[appDelegate selectTask:appDelegate.intForPid];
if (!indexPath.row)
{
[tblView beginUpdates];
//only first row toggles expand/collapse
[tblView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger sections = indexPath.section;
BOOL currentlyExpanded = [expandedSections containsIndex:sections];
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
if (currentlyExpanded)
{
rows = [self tableView:tblView numberOfRowsInSection:sections];
[expandedSections removeIndex:sections];
}
else
{
[expandedSections addIndex:sections];
rows = [self tableView:tblView numberOfRowsInSection:sections];
}
for (int i=1; i<rows; i++)
{
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:sections];
[tmpArray addObject:tmpIndexPath];
}
UITableViewCell *cell = [tblView cellForRowAtIndexPath:indexPath];
if (currentlyExpanded)
{
[tblView deleteRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationTop];
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor blackColor] type:DTCustomColoredAccessoryTypeDown];
}
else
{
[tblView insertRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationTop];
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor blackColor] type:DTCustomColoredAccessoryTypeUp];
}
[tblView endUpdates];
}
}
It gives error:
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1070
2013-03-20 19:14:00.102 Daily Achiever[2886:c07] * 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 (3) 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, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Your problem is in these lines of code:
[tblView deleteRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationTop];
and
[tblView insertRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationTop];
The crash that you posted was due to the first one. In these lines, you are trying to insert/delete rows from the table, but your - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section method does not change correspondingly.
It looks like you want to add/remove items from your appDelegate.array_task array whenever you are adding/removing cells from the table (as this is the array from which you are determining the row count).
As a side note, the line:
if ([appDelegate.array_task count]==0) {
return 0;
}
is not doing anything, because you have else return [appDelegate.array_task count] which means that 0 will be returned if [appDelegate.array_task count]==0 anyway.
while adding sections use this code
NSArray *insertIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:2 inSection:0],
[NSIndexPath indexPathForRow:3 inSection:0],
nil];
for inserting rows
[tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
if u are adding two sections
[tableView insertSections:[NSIndexSet indexSetWithIndex:indexPath.section + 1] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView insertSections:[NSIndexSet indexSetWithIndex:indexPath.section + 2] withRowAnimation:UITableViewRowAnimationAutomatic];
same way delete sections
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:YES];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section - 1] withRowAnimation:YES];
rows delete
[tableView deleteRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
Related
Trying to expand the sections each section will have two rows when expanded. It is giving crash. Below is code am trying.
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.mArrQues count];
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(!helpOn)
return 1;
else
if(section == selectedCellIndexPath)
{
return 2;
}
else{
return 1;
}
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CellIdentifier";
UITableViewCell *cell;
cell = [self.mHelpTable dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
else{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UIView* myBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
myBackgroundView.backgroundColor = [UIColor colorWithRed:240.0/255.0 green:240.0/255.0 blue:240.0/255.0 alpha:1.0];
cell.backgroundView = myBackgroundView;
//[cell addSubview:myBackgroundView];
if(!helpOn)
{
cell.textLabel.text = [self.mArrQues objectAtIndex:indexPath.section];
}
else
{
if(indexPath.row == 0)
{
cell.textLabel.text = [self.mArrQues objectAtIndex:indexPath.section];
}
else{
cell.textLabel.text = [self.mArrAns objectAtIndex:indexPath.section];
}
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
helpOn = !helpOn;
int ind = indexPath.section;
if(ind == selectedCellIndexPath)
{
}
else{
helpOn = 1;
}
if(helpOn)
{
selectedCellIndexPath = indexPath.section;
[self.mHelpTable reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
else
{
if(indexPath.row == 0)
{
//selectedCellIndexPath = indexPath.section;
[self.mHelpTable reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
}
Error :
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 (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).'
As you are changing the number of cells at section, you need to wrap the reload operation with beginUpdates and endUpdates as well as specify the cells insertion and removal with insertRowsAtIndexPaths:withRowAnimation and deleteRowsAtIndexPaths:withRowAnimation:.
Alternatively you can use 'reloadData` to reload all the cells, however there will be problems either with animation or user experience if you use it.
Remove this from your code.
else{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
There is no need to alloc your cell if it is nil, tableview will reuse from previous cell in this line
cell = [self.mHelpTable dequeueReusableCellWithIdentifier:cellIdentifier];
AND
Make in .h
int selectedCellIndexPath;
BOOL selected;
in .m
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section==selectedCellIndexPath)
{
//selected > this is because initialy selectedCellIndexPath is 0 and section is also 0
if (selected) {
return 2;
}
else{
return 1;
}
}
else{
return 1;
}
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CellIdentifier";
UITableViewCell *cell;
cell = [self.mHelpTable dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UIView* myBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
myBackgroundView.backgroundColor = [UIColor colorWithRed:240.0/255.0 green:240.0/255.0 blue:240.0/255.0 alpha:1.0];
cell.backgroundView = myBackgroundView;
//[cell addSubview:myBackgroundView];
//if(!helpOn)
if (indexPath.section!=selectedCellIndexPath)
{
cell.textLabel.text = [mArrQues objectAtIndex:indexPath.section];
}
else
{
if(indexPath.row == 0)
{
cell.textLabel.text = [mArrQues objectAtIndex:indexPath.section];
}
else{
cell.textLabel.text = [mArrAns objectAtIndex:indexPath.section];
}
}
//cell.textLabel.text = [self.mArrQues objectAtIndex:indexPath.section];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selected= !selected;
selectedCellIndexPath = indexPath.section;
//selectedCellIndexPath = indexPath.row;
[self.mHelpTable reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
I have 2 sections and I am trying to make it so when you click the checkbox of a cell in one of the sections, it goes to the other section (ex: section 1->section 2)
here is some relevant code of mine:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (!cell)
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"UITableViewCell"];
if([indexPath section] == 0){
cell.textLabel.text = [[[taskArray objectAtIndex:[indexPath row]] taskName] uppercaseString];
cell.imageView.image = [UIImage imageNamed:#"checkboxtry2.png"];
} else if ([indexPath section] == 1) {
cell.textLabel.text = [[[completedArray objectAtIndex:[indexPath row]] taskName] uppercaseString];
cell.imageView.image = [UIImage imageNamed:#"checkboxtry2selected.png"];
}
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handlechecking:)];
[cell.imageView addGestureRecognizer:tap];
cell.imageView.userInteractionEnabled = YES;
return cell;
}
-(void)handlechecking:(UITapGestureRecognizer *)t{
CGPoint tapLocation = [t locationInView:self.tableView];
NSIndexPath *tappedIndexPath = [self.tableView indexPathForRowAtPoint:tapLocation];
NSIndexPath *newIndexPath = nil;
if (tappedIndexPath.section == 0) {
[completedArray addObject:[taskArray objectAtIndex:tappedIndexPath.row]];
[taskArray removeObject:[taskArray objectAtIndex:tappedIndexPath.row]];
newIndexPath = [NSIndexPath indexPathForRow:tappedIndexPath.row inSection:1];
}
else {
[taskArray addObject:[completedArray objectAtIndex:tappedIndexPath.row]];
[completedArray removeObject:[completedArray objectAtIndex:tappedIndexPath.row]];
newIndexPath = [NSIndexPath indexPathForRow:tappedIndexPath.row inSection:0];
}
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:tappedIndexPath] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}
I have two arrays: taskArray which handles objects in section 0 and completedArray which handles objects in section 1.
I am getting the error * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
2 things.
You are adding gesture recognisers repeatedly to your table view cells even when they have been re-used and already have one.
Also in your gesture recogniser target you could do something like this which might be more reliable:
UITableViewCell *cell = [[t.view superview] superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
I had a working tableview where I could double-tap a cell and it would add an 'action' cell below which had four buttons programmed on it.
Today I added alphabetic sections to the tableview and a section index and I can no longer get this functionality to work.
I've added a whole range of NSLogs to the code to try and find the problem and I can't, it seems to be trying to add a row in the same section and one row further down than the cell tapped, so I'm not sure what the problem is. Would anyone have any idea what I'm doing wrong?
If anyone can shed any light on this I would be hugely appreciative. (And apologies if my code is cumbersome or hard to follow, I'm new to this so feel free to suggest what I can improve!)
- (void)viewDidLoad
{
//I start with an array of objects, so I created two arrays; one containing the first letters of each Name, and a list of the number of objects that start with each of those names.
nameIndex = [[NSMutableArray alloc] init];
nameIndexCount = [[NSMutableDictionary alloc]init];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [nameIndex count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.actionRowIndexPath) {
//Returns first letter of the section
NSString *alphabet = [nameIndex objectAtIndex:section];
//Returns the number of entries starting with that letter
NSString *numberofRows = [nameIndexCount objectForKey:alphabet];
int intNumberOfRows = ([numberofRows integerValue] + 1);
return intNumberOfRows;
} else {
NSString *alphabet = [nameIndex objectAtIndex:section];
NSString *numberofRows = [nameIndexCount objectForKey:alphabet];
int intNumberOfRows = [numberofRows integerValue];
return intNumberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"newTableViewCell"];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"newTableViewCell"];
}
//Configure the cell
UIImageView *imageView = [[UIImageView alloc]initWithFrame:cell.frame];
UIImage *image = [UIImage imageNamed:#"LightGrey.png"];
imageView.image = image;
if ([indexPath isEqual:self.actionRowIndexPath]) {
// Four UIButtons coded programmatically
} else {
Contact *p = [[[ContactStore sharedStore]allContacts]objectAtIndex:totalNumberOfRows];
NSString *firstAndLastName = [NSString stringWithFormat:#"%# %#", [p firstName], [p lastName]];
indexPath = [self modelIndexPath:indexPath];
cell.backgroundView = imageView;
// [cell.imageView setImage:smallThumbnailImage];
[cell.imageView setImage:[p thumbnail]];
[[cell textLabel]setBackgroundColor:[UIColor clearColor]];
[[cell textLabel]setText:firstAndLastName];
[[cell detailTextLabel]setBackgroundColor:[UIColor clearColor]];
[[cell detailTextLabel]setText:[p phoneNumber]];
totalNumberOfRows = totalNumberOfRows + 1;
}
return cell;
}
#pragma mark - Action Row Support
-(NSIndexPath *)modelIndexPath: (NSIndexPath *)indexPath
{
if (self.actionRowIndexPath == nil) {
return indexPath;
}
if ([indexPath row] > [self.actionRowIndexPath row]) {
return [NSIndexPath indexPathForRow:([indexPath row] - 1) inSection:indexPath.section];
}
return indexPath;
}
- (void)handleDoubleTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"Double tap");
CGPoint p = [recognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
NSIndexPath *pathToDelete = self.actionRowIndexPath;
_selectedIndexPath = [self modelIndexPath:_selectedIndexPath];
//Is the user deselecting current row?
if (_actionRowIndexPath) {
[self.tableView deselectRowAtIndexPath:_selectedIndexPath animated:NO];
self.selectedIndexPath = nil;
self.actionRowIndexPath = nil;
} else {
//Selecting a new row
self.selectedIndexPath = indexPath;
self.actionRowIndexPath= [NSIndexPath indexPathForRow:([indexPath row] + 1) inSection:[indexPath section]];
}
[self.tableView beginUpdates];
if (pathToDelete) {
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:pathToDelete] withRowAnimation:UITableViewRowAnimationAutomatic];
}
if (self.actionRowIndexPath) {
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.actionRowIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[self.tableView endUpdates];
}
After you get the IndexPath you need to get the IndexPath.row and IndexPath.section and accordingly you need to add the object into your array at the desired index. For example: if you double tap the 2nd row in the 1st section then you need to add the object at index 4 of the array corresponding to the 1st section and then reload table. The cell would be added to the 3rd index of the 1st section.
I'm encountering the following error when I delete the last record from a UITableView.
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 (3) 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,
1 deleted) and plus or minus the number of rows moved into or out of
that section (0 moved in, 0 moved out).'
My goal is to show "No Record found" if the table array is empty.
This is the code I'm using. When I delete the last record from table array the app crashes. How is it possible to reload the table and show "No Record Found" label?
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([idArray count]==0) {
return 3;
}
else
{
return [idArray count];
}
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"array count %d",[idArray count]);
if ([idArray count] == 0) {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.textAlignment = UITextAlignmentCenter;
tableView.userInteractionEnabled = NO;
self.navigationItem.leftBarButtonItem.enabled = NO;
NSUInteger row = [indexPath row];
switch (row) {
case 0:
cell.textLabel.text = #"";
break;
case 1:
cell.textLabel.text = #"";
break;
case 2:
cell.textLabel.text = #"No Records Found";
break;
default:
break;
}
return cell;
}
else
{ static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
tableView.userInteractionEnabled = YES;
self.navigationItem.leftBarButtonItem.enabled = YES;
// Set up the cell
identify *idItems = [idArray objectAtIndex:indexPath.row];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd MMM,yyyy"];
NSString *dateStr = [formatter stringFromDate:idItems.Date];
UIImageView *accDis = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Arrow.png"]];
cell.accessoryView = accDis;
self.idTableView.separatorColor = [UIColor colorWithRed:150.0/255.0 green:150.0/255.0 blue:150.0/255.0 alpha:1];
cell.textLabel.textColor = [UIColor blackColor];
cell.textLabel.font = [UIFont boldSystemFontOfSize:18];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.detailTextLabel.textColor = [UIColor colorWithRed:100.0/255.0 green:100.0/255.0 blue:100.0/255.0 alpha:1];
cell.detailTextLabel.font = [UIFont italicSystemFontOfSize:16];
cell.detailTextLabel.adjustsFontSizeToFitWidth = YES;
NSString *detailText = [NSString stringWithFormat:#"%# - %#",dateStr,idItems.GeoCode];
if (idItems.Image == NULL) {
cell.imageView.image = [UIImage imageNamed:#"icon58x58.png"];
}
else
{
//pass image to fix size 50 X 50
//UIImage *newImage = [self postProcessImage:idItems.Image];
cell.imageView.image = idItems.thumb;//newImage;
cell.imageView.contentMode=UIViewContentModeScaleAspectFill;
}
cell.textLabel.text = idItems.TypeName;
cell.detailTextLabel.text = detailText;
return cell;
}
}
- (void)tableView:(UITableView *)tv commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if(editingStyle == UITableViewCellEditingStyleDelete) {
if ([idArray count] >=1)
{
[idTableView beginUpdates];
//Get the object to delete from the array.
identifyObject = [appDelegate.idArray objectAtIndex:indexPath.row];
//Delete the object from the table.
[self.idTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[appDelegate removeID:identifyObject];
if ([idArray count] == 0) {
[self.idTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
[idTableView endUpdates];
}
}
}
The problem is that a tableview expects the operations performed on the view to match the data source. You have one record in the table, and you remove it. The tableview is expecting the datasource to now contain zero records, but because of your "no records found" logic, it actually returns a value of 3, hence the consistency error, and your crash.
The bug seems to be this part:
if ([idArray count] == 0) {
[self.idTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
I assume this was intended to insert the "no records found" row into the table when the last line is deleted, but since your "no records found" actually spans three rows, you need to insert three rows here instead, like this:
if ([idArray count] == 0) {
[self.idTableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:0 inSection:indexPath.section],
[NSIndexPath indexPathForRow:1 inSection:indexPath.section],
[NSIndexPath indexPathForRow:2 inSection:indexPath.section],
nil] withRowAnimation:UITableViewRowAnimationFade];
}
For you own sanity however, can I suggest a different approach? Rather than trying to keep your table and datasource in sync whilst juggling these fake three rows of data that are only there for display purposes, why not just insert a UILabel into your view hierarchy (either in front of or behind the tableview) that says "no records found" and show/hide it based on whether the table has any data? That way you can precisely control its position and appearance without having to screw around with your datasource logic.
General rules for dealing with deleting rows are:
Deal with your model
Deal with row's animation
So for example:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSInteger row = [indexPath row];
[yourModel removeObjectAtIndex:row]; // you need to update your model
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
Now, in my opinion the correct code could be the following (I've written some comments to guide you).
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//Get the object to delete from the array.
identifyObject = [appDelegate.idArray objectAtIndex:indexPath.row];
[appDelegate removeID:identifyObject]; // update model first
// now you can check model count and do what you want
if ([appDelegate.idArray count] == 0) // I think you mean appDelegate.idArray
{
// do what you want
// with [self.idTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else
{
[self.idTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
}
Hope it helps.
I was using same approach where I used a cell for "No rows" warning.
For me, this worked:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[favs removeObjectAtIndex:indexPath.section];
if ([favs count] == 0) {
[tableView reloadRowsAtIndexPaths:[[NSArray alloc]initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
[tableView setEditing:NO animated:YES];
// Remove Edit bar button item
self.navigationItem.rightBarButtonItem = nil;
}
else {
// Animate the deletion from the table.
[tableView deleteRowsAtIndexPaths:[[NSArray alloc]initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
}
}
}
I have created one button with action to add a row to the UITableView at run time but my code is not working. I can see the row animating down, but it's shown animated only on my UITableView row is not added. What can I do in this code to see the row added on cell?
I have 4 sections and I want to add row for 1 section on row 0 and 2 section on row 0:
-(IBAction)add:(id)sender
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
NSArray* path = [NSArray arrayWithObject:indexPath];
// fill paths of insertion rows here
[self.mytableview beginUpdates];
[self.mytableview insertRowsAtIndexPaths:path withRowAnimation:UITableViewRowAnimationBottom];
[self.mytableview deleteRowsAtIndexPaths:path withRowAnimation:UITableViewRowAnimationBottom];
[self.mytableview endUpdates];
[self.mytableview reloadData];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
NSInteger rows;
if (section==0) {
rows = 4;
//return rowForSectionOne;
//rows=rowForSectionOne++;
}
if (section == 1)
{
rows = 1;
}
return rows;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [mytableview dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
if ([indexPath row] == 0 && [indexPath section] == 0)
{
cell.textLabel.text=#"Title";
cell.accessoryView = textField;
titlename=textField.text;
[[cell imageView] setImage:[UIImage imageNamed:#"DetailViewDue.png"]];
NSLog(#"******:%#",titlename);
}
if ([indexPath row] == 1 && [indexPath section] == 0)
{
cell.textLabel.text=#"Tags";
cell.detailTextLabel.text=app.Tags;
[[cell imageView] setImage:[UIImage imageNamed:#"DetailViewTag.png"]];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if ([indexPath row] == 2 && [indexPath section] == 0)
{
cell.textLabel.text=#"Notes";
cell.detailTextLabel.text=app.Notes;
[[cell imageView] setImage:[UIImage imageNamed:#"DetailViewNote.png"]];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"dd/MM/yyyy"];
fromDate = [[dateFormat stringFromDate:selectionData.fromDateSelected]retain];
if ([indexPath row] == 3 && [indexPath section] == 0)
{
cell.textLabel.text=#"DueDate";
cell.detailTextLabel.text=fromDate;
[[cell imageView] setImage:[UIImage imageNamed:#"DetailViewDue.png"]];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if ([indexPath row] == 0 && [indexPath section] == 1)
{
cell.textLabel.text=#"Attach";
}
return cell;
}
Well you are doing it right. Lets say when the button is pressed -(IBAction)add:(id)sender is invoked. then compose indexPath with the proper row & section. Here section is 0,1,2,3 (since you have 4 sections -
NSIndexPath *indexPath0 = [NSIndexPath indexPathForRow:0 inSection:0];
NSIndexPath *indexPath1 = [NSIndexPath indexPathForRow:0 inSection:1];
NSIndexPath *indexPath2 = [NSIndexPath indexPathForRow:0 inSection:2];
NSIndexPath *indexPath3 = [NSIndexPath indexPathForRow:0 inSection:3];
//put these indexpaths in a NSArray
[tableView insertRowsAtIndexPaths:array withRowAnimation:UITableViewRowAnimationNone];
This should update the table. No need to do reloadData on the table as you are only adding one row (& not changing the entire table). Also make sure the dataSource has this new added entry per section otherwise your app will crash
You only have to add few lines of code in "cellForRowAtIndexPath" method
if(cell ==nil)
{
cell =[[UITableViewAlloc alloc]initWithStyle.... ]
}
int theRow = indexPath.row;
if(indexPath.section == 1) theRow += 3;
if(indexPath.section == 2) theRow += 5;
if(indexPath.section == 3) theRow += 4;
if(indexPath.section == 4) theRow += 3;
//load the view in it
cell.textLable . text = [<your object> objectAtIndexPath.row];
return cell;
Here you can add rows as many as you want....