Reputation: 387
I'm trying to build a table with cells that list an array in UILabels. So each cell will have its size and amount of labels determined by the number of objects in that array. However, I'm running into an issue where the content is initially input correctly, but then as the table cells get recycled during the scroll, the content doesn't clear.
Here's my entire implementation. If someone could please give me an explanation as to how I can prevent the labels from being retained during the recycling process I'd really appreciate it. Thank you.
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *tableView;
}
@end
ViewController.m
#import "ViewController.h"
#import "CustomCell.h"
@interface ViewController () {
NSArray *myTableArray;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Set up View
self.view = [[UIView alloc] initWithFrame: [UIScreen mainScreen].applicationFrame];
self.view.backgroundColor = [UIColor whiteColor];
self.view.clipsToBounds = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
// Set up Table
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
tableView = [[UITableView alloc] initWithFrame:frame style:UITableViewStylePlain];
tableView.backgroundColor = [UIColor clearColor];
tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
tableView.dataSource = self;
tableView.delegate = self;
[tableView registerClass:[CustomCell class] forCellReuseIdentifier:@"CustomCell"];
[self.view addSubview:tableView];
//Set up dummy array for cells (in my actual app I'm pulling from Core Data)
NSArray *cell1 = [[NSArray alloc]initWithObjects:@"Some Text", nil];
NSArray *cell2 = [[NSArray alloc]initWithObjects:@"Different", @"Text", nil];
NSArray *cell3 = [[NSArray alloc]initWithObjects:@"Lorem...", nil];
NSArray *cell4 = [[NSArray alloc]initWithObjects:@"Thanks", @"for your", @"help", nil];
NSArray *cell5 = [[NSArray alloc]initWithObjects:@"A bit more", @"text", nil];
NSArray *cell6 = [[NSArray alloc]initWithObjects:@"Bunch of", @"junk text", nil];
NSArray *cell7 = [[NSArray alloc]initWithObjects:@"So long", @"and thanks", @"for all", @"the fish", nil];
NSArray *cell8 = [[NSArray alloc]initWithObjects:@"Ipsum..", nil];
NSArray *cell9 = [[NSArray alloc]initWithObjects:@"Peter Pan", @"killed", @"The Lost Boys", nil];
NSArray *cell10 = [[NSArray alloc]initWithObjects:@"All Dogs", @"Go to Heaven", @"Disney", nil];
myTableArray = [[NSArray alloc]initWithObjects:cell1, cell2, cell3, cell4, cell5, cell6, cell7, cell8, cell9, cell10, nil];
NSLog(@"%@",myTableArray);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return myTableArray.count;
}
- (CGFloat)tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *arr = [myTableArray objectAtIndex:indexPath.row];
return 60 * arr.count;
}
- (UITableViewCell*)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"CustomCell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (!cell)
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
// Set up the labels
[cell setLabels:myTableArray[indexPath.row]];
return cell;
}
@end
CustomCell.h
#import <UIKit/UIKit.h>
@interface CustomCell : UITableViewCell
- (void)setLabels:(NSArray *)labels;
@end
CustomCell.m
#import "CustomCell.h"
@implementation CustomCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)setLabels:(NSArray *)labels {
int labelHeight = 60;
int y = 0;
for (NSString *string in labels) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, y, self.bounds.size.width-20, labelHeight)];
label.text = string;
label.font = [label.font fontWithSize:20];
y += labelHeight;
[self.contentView addSubview:label];
}
}
@end
Upvotes: 1
Views: 4685
Reputation: 57050
That's because you are adding a new UILabel
subview without removing the old one.
Why are you adding new labels? Use the already existing label. Since you are using UITableViewCellStyleDefault
, the cell already contains several labels. Use self.textLabel.text = string
instead.
If you wish to keep using a custom label, you should remove all subviews in the cell's prepareForReuse
(don't forget to call the super implementation of prepareForReuse
). Just remember, that since you have defined the cell as UITableViewCellStyleDefault
, it will have other subviews that you should not remove.
Upvotes: 3
Reputation: 62062
In your CustomCell.m
:
- (void)prepareForReuse {
[super prepareForReuse];
for(UIView *subview in [self.contentView subviews]) {
[subview removeFromSuperview];
}
}
prepareForReuse
is a method called on cells as the table view is dequeuing them for reuse.
I'll assume that you've minimized what you're actually doing to a very simplistic example, because otherwise, as Leo Natan has suggested, you should simply be using the existing labels.
Upvotes: 10
Reputation: 6952
You should remove all labels before add labels in reused cell.
- (UITableViewCell*)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"CustomCell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (!cell)
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
for (UIView * subView in [cell.contentView subviews]) {
if ([subView isKindOfClass:[UILabel class]]) {
[subView removeFromSuperview] ;
}
}
// Set up the labels
[cell setLabels:myTableArray[indexPath.row]];
return cell;
}
Upvotes: -1