UITableView cells take content from others cells - iphone

My UITableView cells take content (images) from others cells. I have no idea why that happening, but I am sure that my mistake is silly. At the image below you can see how it looks. Cells on the top take images from the cells on the bottom (facebook and twitter icons).
Here is my code for cellForRowAtIndexPath:
- (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];
}
NSDictionary *dictionary = [mainArray objectAtIndex:indexPath.section];
NSArray *array1 = [dictionary objectForKey:#"stuff"];
NSString *cellValue = [array1 objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue; // загаловок клетки
cell.textLabel.font = [UIFont fontWithName:#"TrebuchetMS-Bold" size:16];
cell.textLabel.textColor = [UIColor colorWithRed:145/256.0 green:0/256.0 blue:0/256.0 alpha:1.0];
cell.backgroundColor = [UIColor whiteColor];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.textLabel.textAlignment = UITextAlignmentLeft;
if (indexPath.section == 0 && indexPath.row == 1)
{
if([[NSUserDefaults standardUserDefaults]boolForKey:#"password"] == YES)
{
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
}
switch(indexPath.section)
{
case 2:
{
cell.textLabel.textAlignment = UITextAlignmentCenter;
}
break;
case 3:
{
if (indexPath.row == 0)
cell.imageView.image = [UIImage imageNamed:#"facebook"];
else if (indexPath.row == 1)
cell.imageView.image = [UIImage imageNamed:#"twitter"];
else if (indexPath.row == 2)
cell.imageView.image = [UIImage imageNamed:#"youtube"];
else
cell.imageView.image = [UIImage imageNamed:#"vk"];
}
break;
default:
break;
}
return cell;
}
How can I fix it ?

Cells are reused, so you have to set the imageView of your cells to nil whenever you don't want an image to appear. Try this:
- (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];
}
NSDictionary *dictionary = [mainArray objectAtIndex:indexPath.section];
NSArray *array1 = [dictionary objectForKey:#"stuff"];
NSString *cellValue = [array1 objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue; // загаловок клетки
cell.textLabel.font = [UIFont fontWithName:#"TrebuchetMS-Bold" size:16];
cell.textLabel.textColor = [UIColor colorWithRed:145/256.0 green:0/256.0 blue:0/256.0 alpha:1.0];
cell.backgroundColor = [UIColor whiteColor];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.textLabel.textAlignment = UITextAlignmentLeft;
cell.imageView.image = nil;
if (indexPath.section == 0 && indexPath.row == 1)
{
if([[NSUserDefaults standardUserDefaults]boolForKey:#"password"] == YES)
{
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
}
switch(indexPath.section)
{
case 2:
{
cell.textLabel.textAlignment = UITextAlignmentCenter;
}
break;
case 3:
{
if (indexPath.row == 0)
cell.imageView.image = [UIImage imageNamed:#"facebook"];
else if (indexPath.row == 1)
cell.imageView.image = [UIImage imageNamed:#"twitter"];
else if (indexPath.row == 2)
cell.imageView.image = [UIImage imageNamed:#"youtube"];
else
cell.imageView.image = [UIImage imageNamed:#"vk"];
}
break;
default:
break;
}
return cell;
}

Related

UITableView redraw issue on scrolling

I have a grouped UITableView that I populate from a list.
On some rows I don't want to have disclosure and on some I need to add label.
But is somehow mix something and add labels on wrong rows and display disclosures at each row.
What am I doing wrong here?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.accessoryView = [[ UIImageView alloc ]
initWithImage:[UIImage imageNamed:#"customdisclosure.png" ]];
}
NSDictionary *dictionary = [_list objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Items"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
if([cell.textLabel.text isEqualToString:#"with label"])
{
cell.accessoryType = UITableViewCellAccessoryNone;
cell.detailTextLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.text = #"label...";
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
else if([cell.textLabel.text isEqualToString: #"No disclosure" ])
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
in your else if clause, you are not clearing the cell.detailTextLabel's text on the reused cell. Set it to nil and you will be fine.
cell.detailTextLabel.text = nil;
You will also need to hide the accessoryView in the else if clause, and unhide it.
cell.accessoryView.hidden = YES;
Overall, I would consider subclassing UITableViewCell so you can override prepareForReuse to reset your cell for the next cellForRowAtIndexPath call.
Guess the issue is with using reusable identifiers. Use different cell identifiers for the cells you do not want accessoryView.
static NSString *CellWithDisclosure = #"CellID_WithDisclosure";
static NSString *CellWithNoDisclosure = #"CellID_NoDisclosure";
NSDictionary *dictionary = [_list objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Items"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
if([cell.textLabel.text isEqualToString:#"with label"])
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellWithDisclosure];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
else if([cell.textLabel.text isEqualToString: #"No disclosure" ])
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellWithNoDisclosure];
cell.accessoryType = UITableViewCellAccessoryNone;
}
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID] autorelease];
}
cell.textLabel.text = cellValue;
return cell;

Incorrect updating content of UITableView

I have TableView which number of rows depends on the number of NSStrings in NSMutableArray friendsNames.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return friendsNames.count + 1;
}
Also each row displays that NSString at the respective index of friendsNames. Everything seems to be very simple. But when i remove a string from friendsNames and use reloadData method then weird thing happens: UITableView removes LAST row, not the row with the string which was just removed from friendsNames. Could you please explain me what's going on and what should i do to fix it?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *MyIdentifier = [NSString stringWithFormat:#"MyIdentifier %i", indexPath.row];
MyTableCell *cell = (MyTableCell *)[friendsList dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[MyTableCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
//create columns
for (int i = 0;i < 6;i++)
[cell.contentView addSubview:[self createGrid:i :indexPath]];
}
return cell;
}
and here is the method which creates columns.it's being called from cellForRowAtIndexPath and it's pretty ugly
- (UILabel *)createGrid:(int)columnIndex :(NSIndexPath *)indexPath
{
CGFloat widths [6] = {35.0,62.0,35.0,35.0,35.0,35.0};//two arrays holding widths of the columns and points where left sides begin
CGFloat leftSides [6] = {0.0,35.0,97.0,132.0,167.0,202.0};
NSArray *titles = [[[NSArray alloc] initWithObjects:#"Status",#"ID",#"Wins",#"Losses",#"Withdrawls",#"Win %", nil] autorelease];
UILabel *columnLabel = [[[UILabel alloc] initWithFrame:CGRectMake(leftSides[columnIndex],0.0,widths[columnIndex], friendsList.rowHeight)] autorelease];
if (indexPath.row == 0)
columnLabel.text = [titles objectAtIndex:columnIndex];
else
{
switch (columnIndex)
{
case 0:
{
BOOL isOnline = [[[receivedUsers objectForKey:[friendsNames objectAtIndex:indexPath.row - 1]] objectAtIndex:0] boolValue];
columnLabel.text = isOnline ?#"On" :#"Off";
}
break;
case 1:
columnLabel.text = [friendsNames objectAtIndex:indexPath.row - 1];
break;
case 2:
columnLabel.text = [NSString stringWithFormat:#"%i",[[[receivedUsers objectForKey:[friendsNames objectAtIndex:indexPath.row - 1]] objectAtIndex:1] intValue] ];
break;
case 3:
columnLabel.text = [NSString stringWithFormat:#"%i",[[[receivedUsers objectForKey:[friendsNames objectAtIndex:indexPath.row - 1]] objectAtIndex:2] intValue] ];
break;
case 4:
columnLabel.text = [NSString stringWithFormat:#"%i",[[[receivedUsers objectForKey:[friendsNames objectAtIndex:indexPath.row - 1]] objectAtIndex:3] intValue] ];
break;
case 5:
columnLabel.text = [NSString stringWithFormat:#"%f",[[[receivedUsers objectForKey:[friendsNames objectAtIndex:indexPath.row - 1]] objectAtIndex:4] floatValue] ];
break;
}
}
columnLabel.layer.borderColor = [[UIColor blackColor] CGColor];
columnLabel.layer.borderWidth = 1.0;
columnLabel.font = [UIFont systemFontOfSize:8.0];
columnLabel.textAlignment = UITextAlignmentCenter;
columnLabel.textColor = [UIColor blackColor];
columnLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight;
return columnLabel;
}
It's a reusable cell problem. Just change your code like that:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *myIdentifier = [NSString stringWithFormat:#"MyIdentifier %i", indexPath.row];
MyTableCell *cell = (MyTableCell *)[friendsList dequeueReusableCellWithIdentifier:myIdentifier];
if (cell == nil) {
//Create a new cell
cell = [[[MyTableCell alloc] initWithFrame:CGRectZero reuseIdentifier:myIdentifier] autorelease];
}
//Configure the cell
//Remove all columns
for(UIVIew *subview in cell.contentView.subviews) {
[subview removeFromSuperview];
}
//Create columns
for (int i = 0;i < 6;i++) {
[cell.contentView addSubview:[self createGrid:i :indexPath]];
}
return cell;
}

iPhone app crashes after execution of cellForRowAtIndexPath method of tableView

App crashes after execution of cellForRowAtIndexPath method of tableView
It goes into:
UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:]
and crashes out.
There is no error shown in Console. It shows EXC_BAD_EXCESS in Status bar of Xcode.
What could be wrong?
EDIT 1:
This is the whole code in my tableView's cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
static NSString *newCellIdentifier = #"NewCell";
UITableViewCell *cell = nil;
NSUInteger row = [indexPath row];
NSUInteger count;
if (searching==YES) {
count = [searchCellTextArray count];
}else {
count = [cellTextArray count];
}
if(row==count)
{
cell = [tableView dequeueReusableCellWithIdentifier:newCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:newCellIdentifier] autorelease];
}
cell.textLabel.text = #"Load more items...";
cell.textLabel.textColor = [UIColor blueColor];
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
UIImage *cellImage = [[UIImage alloc] init];
NSString *imgName;
//Searching
if(searching==YES && [searchCellTextArray count] != 0)
{
NSString *decodedImageName = [NSString stringWithUTF8String:[[[showSearchImageArray objectAtIndex:indexPath.row]valueForKey:#"image"] cStringUsingEncoding:[NSString defaultCStringEncoding]]];
imgName = decodedImageName;
cell.textLabel.textColor = [UIColor redColor];
cell.textLabel.text=[searchCellTextArray objectAtIndex:indexPath.row];
cell.detailTextLabel.font= [UIFont boldSystemFontOfSize:18];
cell.detailTextLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.detailTextLabel.numberOfLines= [lableNameArray count]+2;
cell.detailTextLabel.text = [searchDetailTextArray objectAtIndex:indexPath.row];
}
else
{ //searching
NSString *decodedImageName = [NSString stringWithUTF8String:[[[showImageArray objectAtIndex:indexPath.row] valueForKey:#"image"] cStringUsingEncoding:[NSString defaultCStringEncoding]]];
imgName = decodedImageName;
cell.textLabel.textColor= [UIColor redColor];
cell.textLabel.text = [cellTextArray objectAtIndex:indexPath.row];
cell.detailTextLabel.font= [UIFont boldSystemFontOfSize:18];
cell.detailTextLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.numberOfLines= [lableNameArray count]+2;
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.detailTextLabel.text = [detailTextArray objectAtIndex:indexPath.row];
}
if (imgName !=(NSString*)[NSNull null] && ![imgName isEqualToString:#""] && ![imgName isEqualToString:#"X"])
{
NSLog(#" Image Name : %#",imgName);
NSString *documentsDirectory = [self getImagePath];
NSError *error1;
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:&error1];
if (files == nil)
{
NSLog(#"Error reading contents of documents directory: %#", [error1 localizedDescription]);
}
for (NSString *file in files)
{
NSLog(#"Loop Entered");
if([file isEqualToString:[NSString stringWithFormat:#"%#_thumb.png",imgName]])
{
NSLog(#"Image: %# %#",file,imgName);
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:file];
cellImage = [UIImage imageWithContentsOfFile:fullPath];
NSLog(#"Full Path: %#",fullPath);
}
}
cell.imageView.image = cellImage;
}
else
{
cell.imageView.image = [UIImage imageNamed:#"GlossaryGhostImg1.png"];
}
}
NSLog(#"Cell For Row At Index Path Done");
return cell;
}
Are there memory leaks here, and have I over-released any objects?
Could be many things: You return a garbage cell. You released your cell too many times. You autoreleased some component of your cell too many times. Sounds like a memory management issue, check your retain/releases carefully. And post your cellForRowAtIndexPath code.
Try to add NSZombie environment variable. Then check your app. May be you will find the root cause of the crash.

UITableViewCell loading issues

i have a UITableViewCell loading 10 images its loads the first 6, then its saying (cell != nil) so it doesnt load the remaining images, but if i remove the "if(cell==nil)" it loads all the images
am i missing something?
thanks
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
AsyncImageView *asyncImageView = nil;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
int section = indexPath.section;
NSMutableArray *sectionItems = [sections objectAtIndex:section];
if (cell == nil) {
NSLog(#"CELL == NIL %#", cell);
int n = ([sectionItems count]) ;
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
int i=0,f=0;
while (i < n)
{
int yy = 4 +f*74;
for(int j=0; j<3;j++){
Item *item = [sectionItems objectAtIndex:i];
int buttonX = 10;
if (i == 0) {
buttonX = 10;
}else {
buttonX = 203
}
CGRect frame;
frame.origin.x = buttonX;
frame.origin.y = yy;
frame.size.width = 107;
frame.size.height = 107;
asyncImageView = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
asyncImageView.tag = ASYNC_IMAGE_TAG;
NSString *urlString = item.image;
NSURL *url = [NSURL URLWithString:urlString];
[asyncImageView loadImageFromURL:url];
[cell.contentView addSubview:asyncImageView];
i++;
}
f = f+1;
}
}
else {
NSLog(#"cell != nill");
asyncImageView = (AsyncImageView *) [cell.contentView viewWithTag:ASYNC_IMAGE_TAG];
}
return cell;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog(#"CELL == NIL %#", cell);
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
CGRect frame = CGRectMake(0,20,30,40);
UIImageView *img = [[[UIImageView alloc] initWithFrame:frame];
img.tag = IMAGE_TAG;
[cell.contentView addSubview:img];
[img release];
}int row = indexPath.row;
UIImageView *myImage = = (UIImageView *) [cell.contentView viewWithTag:IMAGE_TAG];
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:#"%d" , row]];
[myImage setImage:image];
return cell;}
UITableViewCells are cached to save memory and allocations costs (hence performance). You only create a cell once and after that you set it contents based on your index path. I've simply created an imageview in the cell and later on set an image depending on the indexpath in that cell (1.png , 2.png etc).
Read the documentation here.
UITableViewCells are re-used to save time and memory, typically, and you're using this paradigm I see. You need to implement the cell != nil case and set up the cell to display the contents based on the indexPath. The cell was previously used to display other content so you need to adjust all indexPath-dependent views in the non-nil cell.

TableView Datasource must return a cell, check code

The debugger threw me this error
UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:
this is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
NSString *text = nil;
NSInteger section = indexPath.section;
NSInteger row = indexPath.row;
switch (section)
{
case PURCHASE_SECTION:
{
static NSString *cellID = #"GenericCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
switch (row)
{
case CATEGORY_ROW:
text = [self.purchase.category valueForKey:#"name"];
cell.textLabel.text = text;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
case TYPE_ROW:
text = [self.purchase.type valueForKey:#"name"];
cell.textLabel.text = text;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
case VENDOR_ROW:
text = [self.purchase.vendor valueForKey:#"name"];
cell.textLabel.text = text;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
case NOTES_ROW:
text = #"Notes";
cell.textLabel.text = text;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
default:
break;
}
break;
}
case ITEMS_SECTION:
{
NSUInteger itemsCount = [purchase.items count];
if (row < itemsCount)
{
static NSString *itemsCellID = #"ItemsCell";
cell = [tableView dequeueReusableCellWithIdentifier:itemsCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:itemsCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
PurchaseItem *item = [items objectAtIndex:row];
cell.textLabel.text = item.name;
cell.detailTextLabel.text = [item.amount formattedDataDisplay];
}
else
{
static NSString *AddItemCellID = #"AddItemCell";
cell = [tableView dequeueReusableCellWithIdentifier:AddItemCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:AddItemCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = #"Add Item";
}
break;
}
case LOCATION_SECTION:
{
text = #"Purchase Location";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.editingAccessoryType = UITableViewCellAccessoryNone;
break;
}
default:
break;
}
cell.textLabel.text = text;
return cell;
}
I just can't seem to spot the error, and I could use a set of fresh eyes.
cell is never set inside case LOCATION_SECTION:.
Also, sometimes you set cell.textLabel.text to a value in a case block, only to reset it to nil later via cell.textLabel.text = text. Surely this isn't intended?
Ok, now i just feel silly, it seems that i left out an important snippet of code involving the dequeueing of cell in the LOCATION_SECTION case. I added it and the error went away, and i would like to thank "rpetrich" for pointing out something i left in the code from a previous time "cell.textlabel.text = text;", and this too needed to be removed, so THANK YOU.