I have a UITableView that's loading some custom UITableViewCells. These custom cells alloc a few UIButtons, and add those buttons to the custom cell's contentView. When repeatedly calling reloadData on the tableView, it seems these UIButtons are slowly leaking memory. I am using ARC, iOS 7.
Here's where the cell is created:
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"PostCell";
PostCell *cell = [_tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[PostCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
return cell;
}
And here's the init method for the custom cell:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.height = 0;
self.backgroundColor = [UIColor clearColor];
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self addInteractionContainer];
}
return self;
}
And finally the addInteractionContainer method (if I don't call this method, I don't see a leak):
- (void)addInteractionContainer {
//interaction container
UIView* interactionContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 80)];
[interactionContainer setBackgroundColor:[UIColor ProseSepiaColor]];
//like button
LikeButton* likeButton = [[LikeButton alloc] initWithFrame:CGRectMake(10, 10, 75, 30) liked:([post.yourVote intValue] > 0)];
[likeButton addTarget:self action:#selector(likePost:) forControlEvents:UIControlEventTouchUpInside];
[interactionContainer addSubview:likeButton];
//comment button
CommentButton* commentButton = [[CommentButton alloc] initWithFrame:CGRectMake(likeButton.frame.origin.x + likeButton.frame.size.width + 10,
10, 105, 30)];
[commentButton addTarget:self action:#selector(segueToComments:) forControlEvents:UIControlEventTouchUpInside];
[commentButton setNumComments:self.post.numComments];
[interactionContainer addSubview:commentButton];
[self.contentView addSubview:interactionContainer];
self.height += interactionContainer.frame.size.height;
}
try this
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"PostCell";
PostCell *cell = [_tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if(cell!=nil)
{
cell=nil;
}
if (cell == nil) {
cell = [[PostCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
return cell;
}
Related
Hi I am very new in iOS and I have created one tablelist on my Viewcontroller and here on my tablelist row I have added one UIlabel programatically, ok that's fine.
And I have added one UIbutton programatically on my "self.view".
Here my main requirement is when I click that button, I want to change UIlabel background color which was added on my tablelist row.
For this I have tried the code bellow, but UIlabel backgroudcolor is not changing.
Please help me.
my code:-
#import "ViewController.h"
#interface ViewController (){
UILabel *label;
}
#end
#implementation ViewController {
UITableView *tableView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self tablelistCreation];
}
//UItableView createtion
-(void)tablelistCreation{
tableView = [[UITableView alloc] initWithFrame:CGRectMake(10, 10, 300, self.420) style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
[self.view addSubview:tableView];
}
//Delegate methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (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] autorelease];
}
cell.textLabel.text = [yourarray objectAtIndex:indexPath.row];
label = [[UILabel alloc] initWithFrame:CGRectMake(40, 30, 300, 50)];
label.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:label];
return cell;
}
//UIbutton createtion
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button .backgroundColor = [UIColor orangecolor];
button.frame = CGRectMake(100, 440, 30, 30);
[self.view addSubview:button];
//button action
-(void)Method:(id)sender{
label.backgroundColor = [UIColor redcolor];
}
Your question was not clear if you want to change the label color on all cell or just some.
Anyway this color change must be made cellForRowAtIndexPath which is where the update / creation of the cell is made.
You can create a variable to inform if you want the color change or not and it check this on cellForRowAtIndexPath.
#implementation ViewController {
UITableView *tableView;
bool changeColor;
}
-(void)Method:(id)sender{
changeColor != changeColor;
[tableview reloadData];
}
- (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] autorelease];
cell.textLabel.text = [yourarray objectAtIndex:indexPath.row];
UILabel label = [[UILabel alloc] initWithFrame:CGRectMake(40, 30, 300, 50)];
[cell.contentView addSubview:label];
}
if (changeColor){
label.backgroundColor = [UIColor redcolor];
}else{
label.backgroundColor = [UIColor clearColor];
}
return cell;
}
if you want change especific labels, you can create a nsarray to control what cell will be change
#interface ViewController (){
UILabel *label;
NSMutableArray *lableArray;
}
#end
#implementation ViewController {
UITableView *tableView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self tablelistCreation];
lableArray=#[].mutableCopy;
}
//UItableView createtion
-(void)tablelistCreation{
tableView = [[UITableView alloc] initWithFrame:CGRectMake(10, 10, 300, self.420) style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
[self.view addSubview:tableView];
}
//Delegate methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (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] autorelease];
label = [[UILabel alloc] initWithFrame:CGRectMake(40, 30, 300, 50)];
label.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:label];
[lableArray addObject:label];
}
cell.textLabel.text = [yourarray objectAtIndex:indexPath.row];
//
// label = [[UILabel alloc] initWithFrame:CGRectMake(40, 30, 300, 50)];
// label.backgroundColor = [UIColor clearColor];
// [cell.contentView addSubview:label];
return cell;
}
//UIbutton createtion
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button .backgroundColor = [UIColor orangecolor];
button.frame = CGRectMake(100, 440, 30, 30);
[self.view addSubview:button];
//button action
-(void)Method:(id)sender{
[lableArray makeObjectsPerformSelector:#selector(setBackground:) withObject:[UIColor redColor]];
// label.backgroundColor = [UIColor redcolor];
}
cell is Reusable so creation should put in cell == nil condition,at every run into the condition will creation a new UILabel ,if you want change all of them ,you should put them in a collection ,such as NSMutableArray...
import "ViewController.h"
#interface ViewController ()
{
UILabel *label;
BOOL isTouchButton;
}
#end
#implementation ViewController {
UITableView *tableView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//UIbutton createtion
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button .backgroundColor = [UIColor orangecolor];
button.frame = CGRectMake(100, 440, 30, 30);
[self.view addSubview:button];
[self tablelistCreation];
}
//UItableView createtion
-(void)tablelistCreation{
tableView = [[UITableView alloc] initWithFrame:CGRectMake(10, 10, 300, self.420) style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
[self.view addSubview:tableView];
}
//Delegate methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (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] autorelease];
}
cell.textLabel.text = [yourarray objectAtIndex:indexPath.row];
label = [[UILabel alloc] initWithFrame:CGRectMake(40, 30, 300, 50)];
label.backgroundColor = [UIColor clearColor];
label.tag = indexPath.row;
if(!isTouchButton)
{
cell.labelUserName.backgroundColor = [UIColor clearColor];
}
else{
cell.labelUserName.backgroundColor = [UIColor redColor];
}
[cell.contentView addSubview:label];
return cell;
}
//button action
-(void)Method:(id)sender
{
if(!isTouchButton)
{
[tablelistCreation reloadData];
isTouchButton = YES;
}
else{
[tablelistCreation reloadData];
isTouchButton = NO;
}
}
I have UITableViewCell class, which contains customLabel and imageView. When I try to load them in my main UITableViewController, nothing happens.
Main UITableViewController contains:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UserTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[cell.customButton setTitle:#"Test" forState:UIControlStateNormal];
PFUser *user = [self.members objectAtIndex:indexPath.row];
cell.customLabel.text = [user objectForKey:#"Name"];
PFFile *userImage = [user objectForKey:#"Image"];
[userImage getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
cell.imageView.image = [UIImage imageWithData:data];
[cell setNeedsLayout];
}
}];
return cell;
}
UserTableViewCell contains:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.customLabel = [[UILabel alloc] initWithFrame:CGRectMake(3, 5, 165, 30)];
self.customLabel.font = [UIFont systemFontOfSize:14];
self.customLabel.textColor = [UIColor blackColor];
self.customLabel.backgroundColor = [UIColor clearColor];
self.customLabel.highlightedTextColor = [UIColor whiteColor];
self.customLabel.adjustsFontSizeToFitWidth = YES;
[self.contentView addSubview:self.customLabel];
self.customButton = [[UIButton buttonWithType:UIButtonTypeCustom] initWithFrame:CGRectMake(180, 5, 40, 30)];
[self.customButton addTarget:self action:#selector(logButtonRow:) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.customButton];
self.imageView2 = [[UIImageView alloc] initWithFrame:CGRectMake(60, 1, 50, 50)];
[self.contentView addSubview:self.imageView2];
}
return self;
}
Have I missed something? I've set Prototype cell identifier to "Cell" and custom class to UserTableViewCell(is this required?)
It appears that you set up your cell in IB, and, if so, initWithStyle:reuseIdentifier: will not be called. If you want to add UI elements to your cell in code, then you should implement initWithCoder instead. Alternatively, you could register your class (in viewDidLoad of your table view controller), and that will cause initWithStyle:reuseIdentifier: to be called (the cell in IB would then be superfluous, since the table view will get the cell from your class definition).
[self.tableView registerClass:[UserTableViewCell class] forCellReuseIdentifier:#"Cell"];
You need to alloc and init your cell when its called the first time:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UserTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(cell == nil)
{
// initialize your cell here
cell = ...
}
...
I have table view in side bar which is similar to facebook app. In my sidebar tableview i have imageview in each row. I want the imageview will be changed when i clicked the cell and it will be retain while for selecting another cell. Here is my code
- (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]autorelease];
}
[[cell.contentView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
UIView * contentView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 60)];
UIImageView * cellImg = [[UIImageView alloc]initWithFrame:CGRectMake(5,8,259, 60)];
[cellImg setImage:[UIImage imageNamed:[menuArr objectAtIndex:indexPath.row]]];
[contentView addSubview:cellImg];
[contentView setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:contentView];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
delegate.sideBarSelectedIndex = indexPath.row;
NSLog(#"delegate.sideBarSelectedIndex: %d",delegate.sideBarSelectedIndex);
[UIView commitAnimations];
if (self.sidebarDelegate) {
NSObject *object = [NSString stringWithFormat:#"ViewController%d", indexPath.row];
[self.sidebarDelegate sidebarViewController:self didSelectObject:object atIndexPath:indexPath];
[delegate.firstLensePageObj timerFunction:indexPath.row];
}
}
Try this in your didSelectRowAtIndexPath delegate method :-
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.imageView.image = [UIImage imageNamed:#"yourImage"];
Try this in cellForRowAtIndexPath.
UIImageView *selectedImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Your Image"]];
cell.selectedBackgroundView = selectedImageView;
Need to capture the selected indexpath in didSelectRowAtIndexPath: method and need to reload the tableview in that method. In cellForRowAtIndexPath need to check the selected index with current index.
- (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]autorelease];
}
[[cell.contentView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
UIView * contentView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 60)];
UIImageView * cellImg = [[UIImageView alloc]initWithFrame:CGRectMake(5,8,259, 60)];
if (delegate.sideBarSelectedIndex == indexpath.row){
//Selected cell
[cellImg setImage:[UIImage imageNamed:[selectedMenuArr objectAtIndex:indexPath.row]]];
}else {
//Unselected cell
[cellImg setImage:[UIImage imageNamed:[menuArr objectAtIndex:indexPath.row]]];
}
[contentView addSubview:cellImg];
[contentView setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:contentView];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
delegate.sideBarSelectedIndex = indexPath.row;
NSLog(#"delegate.sideBarSelectedIndex: %d",delegate.sideBarSelectedIndex);
[UIView commitAnimations];
if (self.sidebarDelegate) {
NSObject *object = [NSString stringWithFormat:#"ViewController%d", indexPath.row];
[self.sidebarDelegate sidebarViewController:self didSelectObject:object atIndexPath:indexPath];
[delegate.firstLensePageObj timerFunction:indexPath.row];
}
}
I have a table view with many cells. In the first cell I placed a UIImageView to hold a pic and next to it a button that will open up a popOver.
My question is: Why is this cell is getting reused in spite of checking (cell==nil) while others are working fine.
The code is as below.
P.S. This is without using storyboard and xib only programatically.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (indexPath.section == 0)
{
if(indexPath.row==0)
{
if(self.imageView==nil)
{
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(30, 2, 50, 40)];
self.imageView.image = [UIImage imageNamed:#"user.png"];
self.imageView.backgroundColor=[UIColor blackColor];
}
[cell.contentView addSubview:self.imageView];
if(self.chooseImage==nil)
{
self.chooseImage = [[UIButton alloc]initWithFrame:CGRectMake(270, 10, 80, 30)];
[self.chooseImage addTarget:self action:#selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
self.chooseImage.backgroundColor = [UIColor blackColor];
[self.chooseImage setTitle:#"CHOOSE" forState:UIControlStateNormal];
}
[cell.contentView addSubview:self.chooseImage];
}
First in code add at end of the method return cell; and use following code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
if(self.imageView==nil)
{
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(30, 2, 50, 40)];
self.imageView.image = [UIImage imageNamed:#"user.png"];
self.imageView.backgroundColor=[UIColor blackColor];
}
[cell.contentView addSubview:self.imageView];
if(self.chooseImage==nil)
{
self.chooseImage = [[UIButton alloc]initWithFrame:CGRectMake(270, 10, 80, 30)];
[self.chooseImage addTarget:self action:#selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
self.chooseImage.backgroundColor = [UIColor blackColor];
[self.chooseImage setTitle:#"CHOOSE" forState:UIControlStateNormal];
}
[cell.contentView addSubview:self.chooseImage];
}
return cell; // this line is not in your code so add this line.
}
As I scroll down the list, all the rows are there, but they keep adding more subviews the more they appear on the visible frame
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *reuse = #"RuleCell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuse];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:reuse];
}
NSUInteger row = indexPath.row;
[self createCell: cell onRow: row];
return cell;
}
- (void) createCell: (UITableViewCell*)cell onRow: (NSUInteger)row
{
UIImageView* bgImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cell_background_spade_active.png"]];
cell.backgroundView = bgImage;
cell.textLabel.hidden = YES;
UILabel* titleLabel = [[UILabel alloc] initWithFrame: CGRectMake(100, CGRectGetHeight(cell.frame) / 2, 200, 50)];
titleLabel.text = [[self.ruleList objectAtIndex: row] objectForKey: TitleKey];
titleLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview: titleLabel];
}
I think you need to execute almost all of the logic that's in createCell: only within the if (cell == nil){ segment of your code. The part that should execute where you're currently calling createCell: is just getting a reference to the titleLabel and setting its text value.
To clarify, here's the kind of modification I'm suggesting (not tested, but should give the right idea):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *reuse = #"RuleCell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuse];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:reuse];
[self setUpCell: cell];
}
NSUInteger row = indexPath.row;
UILabel *titleLabel = (UILabel *)[cell.contentView viewWithTag:42];
titleLabel.text = [[self.ruleList objectAtIndex: row] objectForKey: TitleKey];
return cell;
}
- (void) setUpCell: (UITableViewCell*)cell
{
UIImageView* bgImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cell_background_spade_active.png"]];
cell.backgroundView = bgImage;
cell.textLabel.hidden = YES;
UILabel* titleLabel = [[UILabel alloc] initWithFrame: CGRectMake(100, CGRectGetHeight(cell.frame) / 2, 200, 50)];
titleLabel.tag = 42;
titleLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview: titleLabel];
}