TableView Reusing the Same Cells - objective-c

In my UITableview, I am receiving a strange error. I have an array of dictionaries named _cellTextArray, and that dictionary contains the keys "textLabel", "detailTextLabel" and "cornerLabel". However I created three UILabel's which are added to the contentView of the cell and their text is set to their corresponding name in the dictionary. My problem is that the textLabels are only retrieving the first 5 objects in the dictionary, and using them for every cell rather than retrieving the object at the index of the cell in the dictionary.
Please could you tell me what I am doing wrong. I have combed through the code a few times, NSLog'ing the dictionaryValues for each indexPath, and they are all correct.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
CheckBox *btn = (CheckBox *)[_checkboxArray objectAtIndex:indexPath.row];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[cell.contentView addSubview:btn];
//I added this code:
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:12.0];
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 3; // 0 means no max.
UIImageView* img = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"gradient7.png"]] autorelease];
[cell setBackgroundView:img];
UILabel *lab = [[[UILabel alloc] initWithFrame:CGRectMake(40, 18, cell.contentView.frame.size.width-15, 22)] autorelease];
[lab setText:[[_cellTextArray objectAtIndex:indexPath.row] objectForKey:#"textLabel"]];
[lab setBackgroundColor:[UIColor clearColor]];
[lab setTextColor:[UIColor whiteColor]];
[lab setAdjustsFontSizeToFitWidth:YES];
[lab setTextAlignment:UITextAlignmentLeft];
[cell.contentView addSubview:lab];
UILabel *dlabl = [[[UILabel alloc] initWithFrame:CGRectMake(5, 54, cell.contentView.frame.size.width- 1, 22)] autorelease];
[dlabl setText:[[_cellTextArray objectAtIndex:indexPath.row] objectForKey:#"detailTextLabel"]];
[dlabl setTextColor:[UIColor colorWithRed:1.0 green:0.80 blue:0.0 alpha:1.0]];
[dlabl setBackgroundColor:[UIColor clearColor]];
// [dlabl setAdjustsFontSizeToFitWidth:YES];
[dlabl setTextAlignment:UITextAlignmentLeft];
[dlabl setFont:[UIFont systemFontOfSize:[lab font].pointSize - 3]];
[cell.contentView addSubview:dlabl];
UILabel *cornerLabel = [[[UILabel alloc] initWithFrame:CGRectMake(cell.contentView.frame.size.width - 40, 19, 40, 20)] autorelease];
[cornerLabel setTextColor:[UIColor whiteColor]];
//[cornerLabel setFont:[UIFont systemFontOfSize:12]];
[cornerLabel setAdjustsFontSizeToFitWidth:YES];
[cornerLabel setBackgroundColor:[UIColor clearColor]];
[cornerLabel setTextAlignment:UITextAlignmentCenter];
[cell.contentView addSubview:cornerLabel];
[cornerLabel setAdjustsFontSizeToFitWidth:YES];
[cornerLabel setText:[[_cellTextArray objectAtIndex:indexPath.row] objectForKey:#"cornerLabel"]];
// Adds image to cell
// UIImageView *imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(100, 5, 140, 50)] autorelease];
// [imageView setImage:[UIImage imageNamed:[[_cellTextArray objectAtIndex:indexPath.row] objectForKey:#"image"]]];
// [cell.contentView addSubview:imageView];
}
// Configure the cell.
return cell;
}

Check Listing 5-3 on this page (iOS Table View Programming Guide) to see how it is done properly.

You are only setting the data when there are no reusable cells. Once they are there, the table view won't ask for a new cell. So your data isn't being set. You are plainly returning the reused cell. You should set all the static properties (which don't depend on the row data) within that cell and bring all assignments outside the if statement. In this case, they seem to be the setText: statements of the three labels.

Related

Adding subviews to UITableViewCells causing issue while scrolling

I'm absolutely stumped on how to fix this issue.
So I have a UITableView and in the delegate method cellForRowAtIndex: I'm adding several subviews to each cell if the cell is nil (the initial building of the table view). Everything works well and the table view is built, however, when I scroll down a little in the application, the app all of a sudden crashes with SIGBART and gives me the error
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSIndexPath setImage:]: unrecognized selector sent to class 0x3c361e68'** It's weird because I'm not even calling a setImage method anywhere in my code.
Here is the code for the delegate method.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UIImageView* imageView;
UILabel* ttitle;
UILabel* ttitle2;
UILabel* ttitle3;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure cell:
// *** This section should configure the cell to a state independent of
// whatever row or section the cell is in, since it is only executed
// once when the cell is first created.
imageView=[[UIImageView alloc]initWithFrame:CGRectMake(10.0, 11.0, 50.0, 50.0)];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
imageView.layer.masksToBounds=YES;
imageView.layer.cornerRadius=5.0;
[cell.contentView addSubview:imageView];
ttitle = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 7.0, 200, 20)] autorelease];
ttitle.textColor= [UIColor blackColor];
ttitle.numberOfLines=1;
ttitle.backgroundColor=[UIColor clearColor];
ttitle.font=[UIFont fontWithName:#"Arial Bold" size:15.0];
[cell.contentView addSubview:ttitle];
if (indexPath.row==0) {
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:#"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.5, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:#"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-8.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:#"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
else{
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:#"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.0, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:#"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-9.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:#"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
}
// Customize cell:
// *** This section should customize the cell depending on what row or section
// is passed in indexPath, since this is executed every time this delegate method
// is called.
imageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[[data objectAtIndex:indexPath.row] valueForKey:#"thumbnail"]]]];
[ttitle setText:[[data objectAtIndex:indexPath.row] valueForKey:#"name"]];
[ttitle2 setText:[[data objectAtIndex:indexPath.row] valueForKey:#"content"]];
NSString* first=[[[data objectAtIndex:indexPath.row] valueForKey:#"hashtag"] stringByAppendingString:#" "];
NSString* second =[first stringByAppendingString:[[data objectAtIndex:indexPath.row] valueForKey:#"place"]];
NSString* third=[second stringByAppendingString:#" "];
NSString* fourth=[third stringByAppendingString:#"¤ "];
NSString* conversion=[[[data objectAtIndex:indexPath.row] valueForKey:#"counter"] stringValue];
NSString* fifth=[fourth stringByAppendingString:conversion];
[ttitle3 setText:fifth];
return cell;
}
Appreciate the help guys!
*UPDATED CODE
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UIImageView* imageView;
UILabel* ttitle;
UILabel* ttitle2;
UILabel* ttitle3;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure cell:
// *** This section should configure the cell to a state independent of
// whatever row or section the cell is in, since it is only executed
// once when the cell is first created.
imageView=[[UIImageView alloc]initWithFrame:CGRectMake(10.0, 11.0, 50.0, 50.0)];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
imageView.layer.masksToBounds=YES;
imageView.layer.cornerRadius=5.0;
imageView.tag=1;
[cell.contentView addSubview:imageView];
ttitle = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 7.0, 200, 20)] autorelease];
ttitle.textColor= [UIColor blackColor];
ttitle.numberOfLines=1;
ttitle.tag=69;
ttitle.backgroundColor=[UIColor clearColor];
ttitle.font=[UIFont fontWithName:#"Arial Bold" size:15.0];
[cell.contentView addSubview:ttitle];
if (indexPath.row==0) {
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:#"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.5, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.tag=70;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:#"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-8.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.tag=71;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:#"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
else{
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:#"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.0, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.tag=70;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:#"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-9.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.tag=71;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:#"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
imageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[[data objectAtIndex:indexPath.row] valueForKey:#"thumbnail"]]]];
[ttitle setText:[[data objectAtIndex:indexPath.row] valueForKey:#"name"]];
[ttitle2 setText:[[data objectAtIndex:indexPath.row] valueForKey:#"content"]];
NSString* first=[[[data objectAtIndex:indexPath.row] valueForKey:#"hashtag"] stringByAppendingString:#" "];
NSString* second =[first stringByAppendingString:[[data objectAtIndex:indexPath.row] valueForKey:#"place"]];
NSString* third=[second stringByAppendingString:#" "];
NSString* fourth=[third stringByAppendingString:#"¤ "];
NSString* conversion=[[[data objectAtIndex:indexPath.row] valueForKey:#"counter"] stringValue];
NSString* fifth=[fourth stringByAppendingString:conversion];
[ttitle3 setText:fifth];
}
else {
imageView =[cell viewWithTag:1];
ttitle=[cell viewWithTag:69];
ttitle2=[cell viewWithTag:70];
ttitle3=[cell viewWithTag:71];
}
//STUFFOUTSIDE
// Customize cell:
// *** This section should customize the cell depending on what row or section
// is passed in indexPath, since this is executed every time this delegate method
// is called.
return cell;
}
The problem is that your local variables are not being initialized when the cell is re-used. Here's the current flow for imageView:
UIImageView* imageView;
if (cell == nil)
{
// Create imageView
imageView=...
}
// If cell is being reused (ie cell is not nil) then imageView is nil at this point.
imageView.image=...
When you are reusing a table view cell, tableView:dequeueReusableCellWithIdentifier: returns an actual cell instead of nil and the initialization of imageView is skipped.
You need to "find" the imageView that is in the reused cell in order to make changes to it.
Therefore, I suggest that you modify your logic like this:
UIImageView* imageView;
if (cell == nil)
{
// Create imageView
imageView=...
}
else
{
imageView = // get a reference to the imageView
}
imageView.image=...
So now, of course, the question is "how?".
A very common way is to set the tag of the view when you create it so that you can easily retrieve it at a later time. You would use this technique like this:
// Use a unique tag number for each subview.
#define MY_IMAGEVIEW_TAG 1000
UIImageView* imageView;
if (cell == nil)
{
// Create imageView
imageView=... // Same as before
imageView.tag = MY_IMAGEVIEW_TAG;
}
else
{
// This is a cell that is being re-used and was previously created.
// Retrieve a reference to the existing image view that is already in the cell
imageView = [cell viewWithTag:MY_IMAGEVIEW_TAG];
}
// Now imageView is "safe" to use whether it is a new cell or one that is reused!
imageView.image=...
NOTE: If you are doing a lot of this, creating a UITableViewCell subclass that has properties for each of these subviews would make the use of tags and viewWithTag unnecessary, as well as make your code easier to read.
#Inafziger has already posted the correct answer to this question, I just want to explain a little bit more in detail why you're seeing this "weird" crash.
I wouldn't recommend the excessive usage of tags, though. It might be a better idea to create a subclass of UITableViewCell.
You're not initializing your imageView and ttitle variables:
UIImageView *imageView; // imageView can point to anything now!
UILabel* ttitle;
Usually, you'd initialize local variables to nil or 0 (whatever makes sense) when you declare them to avoid such dangling pointers.
Because you're reusing your table view cells cell won't always be nil and your if-clause won't be executed:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) { // Won't be executed if the cell could be dequeued!
...
imageView = ...;
}
Hence, if cell can be dequeued, your imageView and ttitle variables have still not been assigned to anything when you use them!
You're then setting the attributes of the views:
imageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[[data objectAtIndex:indexPath.row] valueForKey:#"thumbnail"]]]];
[ttitle setText:[[data objectAtIndex:indexPath.row] valueForKey:#"name"]];
[ttitle2 setText:[[data objectAtIndex:indexPath.row] valueForKey:#"content"]]
imageView.image = ...; is the same as calling [imageView setImage:...];. You can read more about that here: http://www.cocoacast.com/cocoacast/?q=node/103
And that's when all comes together: imageView isn't initialized and you're calling -setImage: on it. Boom, crash!
In your case imageView points to the NSIndexPath class. This could be anything, though.
Because of that you're effectively calling -setImage: on the NSIndexPath class (equivalent to: +[NSIndexPath setImage:]) and the app crashes with the +[NSIndexPath setImage:]: unrecognized selector sent to class 0x3c361e68 error message.

Weird tableViewCell issue on iOS 6

These "pipe" characters are appearing in some of my cells on my table view, but only on iOS 6. The first screenshot shows the issue on iOS 6, and the lower screenshot is iOS 4.3:
I appreciate any help offered.
Here is the code I'm using:
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%d%d", indexPath.section, indexPath.row];
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIView *clearColor = [[UIView alloc] init];
clearColor.backgroundColor = [UIColor clearColor];
cell.selectedBackgroundView = clearColor;
}
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 243.5, 25)];
[label1 setFont:[UIFont fontWithName:#"Helvetica-Bold" size:16.0]];
[label1 setTextColor:[UIColor blackColor]];
label1.text = [[self.tableDataSource objectAtIndex:indexPath.row] objectForKey:#"Name"];
[cell addSubview:label1];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(253.5, 10, 243.5, 25)];
[label2 setFont:[UIFont fontWithName:#"Helvetica-Bold" size:16.0]];
[label2 setTextColor:[UIColor blackColor]];
label2.text = [[self.tableDataSource objectAtIndex:indexPath.row] objectForKey:#"Email"];
[cell addSubview:label2];
UILabel *label3 = [[UILabel alloc]initWithFrame:CGRectMake(507, 10, 243.5, 25)];
[label3 setFont:[UIFont fontWithName:#"Helvetica-Bold" size:16.0]];
[label3 setTextColor:[UIColor blackColor]];
label3.text = [[self.tableDataSource objectAtIndex:indexPath.row] objectForKey:#"Phone"];
[cell addSubview:label3];
UILabel *label4 = [[UILabel alloc]initWithFrame:CGRectMake(760.5, 10, 243.5, 25)];
[label4 setFont:[UIFont fontWithName:#"Helvetica-Bold" size:16.0]];
[label4 setTextColor:[UIColor blackColor]];
label4.text = [[self.tableDataSource objectAtIndex:indexPath.row] objectForKey:#"Business"];
[cell addSubview:label4];
return cell;
}
click for larger image
Any specific reason you're using UILabels? I checked the code for an iOS6 application I have and I used NSStrings.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *newTitle = #"my string";
cell.textLabel.text = newTitle;
}
Turns out I had to set each label's background color to clear:
label.backgroundColor = [UIColor clearColor];
set clear background colour for labels
label.backgroundColor = [UIColor clearColor];

Altering selected state for UITableViewCell

I've got a standard UITableView where each cell is a custom UIView. Everything works fine, except when the cell is selected, it turns blue (as expected) but the UIView is hidden!
How can I change the contents of the view to be visible when the cell is selected?
- (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];
}
UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 100)];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, 300, 40)];
[headerLabel setText:[[[todayCollection events]objectAtIndex:indexPath.row]name]];
[headerLabel setFont:[UIFont boldSystemFontOfSize:22]];
headerLabel.highlightedTextColor = [UIColor whiteColor];
UILabel *venueLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 40, 300, 20)];
[venueLabel setText:[[[[todayCollection events]objectAtIndex:indexPath.row]venue]name]];
[venueLabel setFont:[UIFont italicSystemFontOfSize:16]];
LBVenueBadge *venueBadge = [[LBVenueBadge alloc] initWithGenre:[[[todayCollection events]objectAtIndex:indexPath.row]genre] frame:CGRectMake(85, 73, 100, 20)];
UIImageView *pinImage = [[UIImageView alloc] initWithFrame:CGRectMake(10, 75, 18, 18)];
[pinImage setImage:[UIImage imageNamed:#"193-location-arrow.png"]];
UILabel *distanceLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, 75, 100, 15)];
[distanceLabel setFont:[UIFont systemFontOfSize:12]];
NSString *distanceString = [[[[todayCollection events]objectAtIndex:indexPath.row]venue]distanceString];
if([[[[todayCollection events]objectAtIndex:indexPath.row]performances]count] == 1)
{
UILabel *performanceLabel = [[UILabel alloc] initWithFrame:CGRectMake(200, 75, 50, 15)];
[performanceLabel setText:[[[[[todayCollection events]objectAtIndex:indexPath.row]performances]objectAtIndex:0]time]];
[performanceLabel setBackgroundColor:[UIColor clearColor]];
[performanceLabel setFont:[UIFont systemFontOfSize:12]];
[containerView addSubview:performanceLabel];
}else{
UILabel *performanceLabel = [[UILabel alloc] initWithFrame:CGRectMake(200, 75, 50, 15)];
[performanceLabel setText:[NSString stringWithFormat:#"%i shows", [[[[todayCollection events]objectAtIndex:indexPath.row]performances]count]]];
[performanceLabel setBackgroundColor:[UIColor clearColor]];
[performanceLabel setFont:[UIFont systemFontOfSize:12]];
[containerView addSubview:performanceLabel];
}
[distanceLabel setText:distanceString];
[containerView addSubview:pinImage];
[distanceLabel setBackgroundColor:[UIColor clearColor]];
[containerView addSubview:distanceLabel];
[headerLabel setBackgroundColor:[UIColor clearColor]];
[containerView addSubview:headerLabel];
[venueLabel setBackgroundColor:[UIColor clearColor]];
[containerView addSubview:venueLabel];
[containerView addSubview:venueBadge];
if(indexPath.row % 2 == 0)
{
[containerView setBackgroundColor:[UIColor colorWithRed:0.239 green:0.239 blue:0.232 alpha:0.05]];
}else{
[containerView setBackgroundColor:[UIColor colorWithRed:0.239 green:0.239 blue:0.232 alpha:0.02]];
}
cell.backgroundView = containerView;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
Thanks,
As the contentView property is readonly, I can add a subview to it instead.
[cell.contentView addSubview:containerView];
You are adding views to the background rather than the contentView of the cell replace this line.
cell.backgroundView = containerView;
with
[cell.contentView addSubview:containerView];

iOS: How to access custom labels on the contentView of an UITableViewCell correctly?

I have a UITableView with each cell being broken into several sections with a different label in each section. The table gets populated by an NSArray of NSDictionaries which contain all the data that populates the cell's labels. This part of the UITableView works great.
The problem arises when I change some of the values in one of the NSDictionaries and then reload the table with the updated NSArray. Normally, when I call [myTableView reloadData]; nothing is updated even though (through debugging) I can see the updated data being processed. But if I change the standard: if (cell == nil) { to if (1) {, in the cellForRowAtIndexPath method, then it works beautifully. I understand why if(1) { works but I do not understand why I cannot reuse the cells and just change the label text.
Why does if (cell == nil) not work? Is it a huge resource drain to re-initialize each cell?
CODE:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"myCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellIdentifier];
if (/*cell == nil*/1) {
// Initialize Custom Cell
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
//// Background View
cellBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 622, 43)];
[cellBackgroundView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"Images/Library/phase_table_cell.png"]]];
//// Name Label
nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 250, 18)];
[nameLabel setBackgroundColor:[UIColor clearColor]];
[cellBackgroundView addSubview:nameLabel];
//// Percent Complete Label
percentCompleteLabel = [[UILabel alloc] initWithFrame:CGRectMake(300, 10, 30, 18)];
[percentCompleteLabel setBackgroundColor:[UIColor clearColor]];
[percentCompleteLabel setTextAlignment:UITextAlignmentCenter];
[cellBackgroundView addSubview:percentCompleteLabel];
//// Overall Status Label
overallStatusLabel = [[UILabel alloc] initWithFrame:CGRectMake(352, 7, 63, 30)];
[overallStatusLabel setBackgroundColor:[UIColor clearColor]];
[overallStatusLabel setFont:[UIFont boldSystemFontOfSize:12.0]];
[overallStatusLabel setLineBreakMode:UILineBreakModeWordWrap];
[overallStatusLabel setNumberOfLines:2];
[overallStatusLabel setTextAlignment:UITextAlignmentCenter];
[cellBackgroundView addSubview:overallStatusLabel];
//// Finish Date Label
finishDateLabel = [[UILabel alloc] initWithFrame:CGRectMake(425, 10, 55, 18)];
[finishDateLabel setBackgroundColor:[UIColor clearColor]];
[finishDateLabel setTextAlignment:UITextAlignmentCenter];
[finishDateLabel setFont:[UIFont systemFontOfSize:12.0]];
[cellBackgroundView addSubview:finishDateLabel];
//// Overall Weight Label
overallWeightLabel = [[UILabel alloc] initWithFrame:CGRectMake(505, 10, 30, 18)];
[overallWeightLabel setBackgroundColor:[UIColor clearColor]];
[overallWeightLabel setTextAlignment:UITextAlignmentCenter];
[cellBackgroundView addSubview:overallWeightLabel];
//// Green Risk View
greenRiskView = [[UIView alloc] initWithFrame:CGRectMake(557, 4, 61, 10)];
[greenRiskView setBackgroundColor:[UIColor greenColor]];
[greenRiskView setHidden:YES];
[cellBackgroundView addSubview:greenRiskView];
//// Yellow Risk View
yellowRiskView = [[UIView alloc] initWithFrame:CGRectMake(557, 17, 61, 10)];
[yellowRiskView setBackgroundColor:[UIColor yellowColor]];
[yellowRiskView setHidden:YES];
[cellBackgroundView addSubview:yellowRiskView];
//// Red Risk View
redRiskView = [[UIView alloc] initWithFrame:CGRectMake(557, 30, 61, 10)];
[redRiskView setBackgroundColor:[UIColor redColor]];
[redRiskView setHidden:YES];
[cellBackgroundView addSubview:redRiskView];
[cell.contentView addSubview:cellBackgroundView];
}
// Get Current Dictionary
NSDictionary *dictForIndexPath = [self.phaseArray objectAtIndex:[indexPath row]];
// Set Elements
[nameLabel setText:[dictForIndexPath objectForKey:#"name"]];
[percentCompleteLabel setText:[dictForIndexPath objectForKey:#"percentComplete"]];
[overallStatusLabel setText:[dictForIndexPath objectForKey:#"overallStatus"]];
[overallWeightLabel setText:[[NSNumber numberWithInt:[[dictForIndexPath objectForKey:#"overallWeight"] intValue]] stringValue]];
//// Create Finish Date String
NSString *finishDateString = [NSString stringWithFormat:#"%#/%#/%#", [dictForIndexPath objectForKey:#"finishDay"], [dictForIndexPath objectForKey:#"finishMonth"], [dictForIndexPath objectForKey:#"finishYear"]];
[finishDateLabel setText:finishDateString];
//// Pick Risk View
NSString *riskColor = [dictForIndexPath objectForKey:#"riskColor"];
if ([riskColor isEqualToString:#"Green"]) {
[greenRiskView setHidden:NO];
[yellowRiskView setHidden:YES];
[redRiskView setHidden:YES];
} else if ([riskColor isEqualToString:#"Yellow"]) {
[greenRiskView setHidden:YES];
[yellowRiskView setHidden:NO];
[redRiskView setHidden:YES];
} else {
[greenRiskView setHidden:YES];
[yellowRiskView setHidden:YES];
[redRiskView setHidden:NO];
}
return cell;
}
Probably you are assigning the value within the if(cell==nil) block? Only the initialization should happen within that block. Move the rest out of it. (Post your complete cellForRow code, if you need more help)
//edit: now, after you posted your code i see your problem:
you are storing all your labels and views in member variables.. but of course that only happens, when the if(cell != nil) block is executed. After that, you always access the same single cell (that was assigned last). So you are updating at least one cell ;)
To fix your problem, work e.g. with tags to get your corresponding views back from the cell. I will show it for your backgroundView, but you have to do it for all of your views (INSTEAD of the member variables. Remove them.)
static NSString *cellIdentifier = #"myCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellIdentifier];
if (cell == nil) {
//// Background View
UIView* cellBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 622, 43)];
cellBackgroundView.tag = 1;
[cellBackgroundView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"Images/Library/phase_table_cell.png"]]];
}
// get the backgroundview from the current cell
UIView* backgroundView = [cell.contentView viewWithTag: 1];
and so on..

UITableViewCell - overlapping with previous cells contents

I have this wierd problem with my table
i Have about 20 cells to display
Each cell is about 84px in height
When i click no the cell, i have set a background colour
The first 4 cells are ok, but when i scroll down and click on the 5th cell, the content of each cell starts to overlap with some other content, usually content from 1st 4 cells.
I belive its some cell reusability or drawing issue. Am not sure how to solve it, i have checked through my code, but i am not changing the cell's content on touch.
Here is my code and will add some pics too
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 104;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [stores count];
}
-(UITableViewCell *)tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CGRect Label1Frame = CGRectMake(5, 5, 250, 30);
CGRect Label2Frame = CGRectMake(6, 42, 220, 20);
CGRect Label3Frame = CGRectMake(6, 62, 220, 20);
CGRect Label4Frame = CGRectMake(240,56, 70, 12);
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}else{
// a cell is being recycled, remove the old edit field (if it contains one of our tagged edit fields)
UIView *viewToCheck = nil;
viewToCheck = [cell.contentView viewWithTag:1];
if (!viewToCheck) {
[viewToCheck removeFromSuperview];
DebugLog(#"View removed");
}
}
//cell.selectionStyle=UITableViewCellSelectionStyleNone;
[cell setSelectedBackgroundView:bgView];
NSInteger row=indexPath.row;
UILabel *lblTemp;
[[cell contentView] clearsContextBeforeDrawing];
//Line 1
lblTemp=[[UILabel alloc] initWithFrame: Label1Frame];
lblTemp.tag=1;
lblTemp.text=[[stores objectAtIndex:row] objectAtIndex:0] ;
lblTemp.numberOfLines=2;
lblTemp.font = [UIFont boldSystemFontOfSize:13];
lblTemp.adjustsFontSizeToFitWidth=YES;
lblTemp.minimumFontSize=12;
lblTemp.textColor = [UIColor grayColor];
[cell.contentView addSubview:lblTemp];
[lblTemp release];
//Line 2
lblTemp = [[UILabel alloc] initWithFrame:Label2Frame];
lblTemp.tag = 2;
lblTemp.text=[[stores objectAtIndex:row]objectAtIndex:1];
lblTemp.font = [UIFont systemFontOfSize:12];
lblTemp.textColor = [UIColor grayColor ];
lblTemp.textAlignment=UITextAlignmentLeft;
lblTemp.adjustsFontSizeToFitWidth=YES;
lblTemp.minimumFontSize=12;
[cell.contentView addSubview:lblTemp];
[lblTemp release];
//Line 3
lblTemp = [[UILabel alloc] initWithFrame:Label3Frame];
lblTemp.tag = 3;
lblTemp.text=[[stores objectAtIndex:row]objectAtIndex:2];
lblTemp.font = [UIFont systemFontOfSize:12];
lblTemp.textColor = [UIColor grayColor ];
[cell.contentView addSubview:lblTemp];
[lblTemp release];
//Phone button
UIButton *phoneButton=[[UIButton alloc] initWithFrame:CGRectMake(240,16,30,30)];
[phoneButton setBackgroundImage:[UIImage imageNamed:#"phone.png"] forState:UIControlStateNormal];
[phoneButton setTag:row];
[phoneButton addTarget:self action:#selector(dialNumber:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:phoneButton];
//ANnotation button
UIButton *annotation=[[UIButton alloc] initWithFrame:CGRectMake(274,16,30,30)];
[annotation setTag:row];
[annotation setBackgroundImage:[UIImage imageNamed:#"tab.png"] forState:UIControlStateNormal];
[annotation addTarget:self action:#selector(openMap:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:annotation];
[annotation release];
//Distance label
//Line 3
lblTemp = [[UILabel alloc] initWithFrame:Label4Frame];
lblTemp.tag = 4;
lblTemp.text=[[stores objectAtIndex:row]objectAtIndex:5];
lblTemp.textAlignment=UITextAlignmentCenter;
lblTemp.font = [UIFont systemFontOfSize:13];
lblTemp.textColor = [UIColor grayColor ];
[lblTemp setAdjustsFontSizeToFitWidth:YES];
[cell.contentView addSubview:lblTemp];
[phoneButton release];
[lblTemp release];
[cell setNeedsLayout];
[cell setNeedsDisplay];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath ];
for(UILabel *lbl in cell.contentView.subviews){
if([lbl isKindOfClass:[UILabel class]]){
lbl.textColor=[UIColor whiteColor];
}
}
//UITableViewCell *cell1;
//NSString *row=[NSString stringWithFormat:#"%d",indexPath.row];
svm = [[storesMapView alloc] initWithNibName:#"storesMapView" bundle:nil];
[svm initWithXML:stores:indexPath.row];
CGRect theFrame = svm.view.frame;
theFrame.origin = CGPointMake(self.view.frame.size.width, 0);
svm.view.frame = theFrame;
theFrame.origin = CGPointMake(0,0);
theFrame.size=CGSizeMake(320,355);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3f];
svm.view.frame = theFrame;
[UIView commitAnimations];
[subView addSubview:svm.view];
backButton.hidden=NO;
}
I figured it out with some trial and error; if this can help some one
In cellforRowAtIndexPath i tried to clear all the cells subview before drawing the cell
//TRY TO REMOVE ALL CONTENT
for(UIView *view in cell.contentView.subviews){
if ([view isKindOfClass:[UIView class]]) {
[view removeFromSuperview];
}
}
I would be happy if someone can point me to some easier way
Thanks
You can use
[[[cell contentView] subviews] makeObjectsPerformSelector: #selector(removeFromSuperview)];
If the cell in not nil, the above code will reduce the time for using the for loop similar to this
for(UIView *eachView in [cell subviews])
[eachView removeFromSuperview];
I also had the same issue.I also had composed tableView with labels.And when I scroll it down the contents got overlapped.But it got solved simply by editing one statement in cellForRowAtIndexPath.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
I think this will solve your problem.
I know this is a bit late, but I had a similar issue where UILabels created for a cell were still part of the cell when it was reused. So each successive update of the tableview created another UILabel on top of the existing one. I moved the creation of the Labels into the if condition as below and it resolved my issue. Hope it helps someone else. Also note no release as I am using ARC.
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cityText = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 100, 20)];
cityText.font = [UIFont fontWithName:#"Arial" size:20];
cityText.textAlignment = UITextAlignmentLeft;
cityText.backgroundColor = [UIColor clearColor];
regionText = [[UILabel alloc] initWithFrame:CGRectMake(10, 40, 100, 20)];
regionText.font = [UIFont fontWithName:#"Arial" size:20];
regionText.textAlignment = UITextAlignmentLeft;
regionText.backgroundColor = [UIColor clearColor];
}
Setting nil to label text on UITableViewCell subclass 's method prepareForReuse() solved my problem -
override func prepareForReuse() {
super.prepareForReuse()
self.label1.text = nil
self.label2.text = nil
....
}
Shared if it helps anyone!