How to Use Reusable Cells in Uitableview for iOS

Reusing cells in UITableView

The right way to do this is to configure the prepareForReuse() method inside the NewsCell class.

override func prepareForReuse() {
super.prepareForReuse()

imageView.image = //Default image
//Whatever other things you need cleared.
}

This method is called whenever a tableView dequeues a cell. So any cached data should be cleared here or it will persist in the dequeued cell unless you manually change it before returning it in the cellForRowAt method.

How to use Reusable Cells in uitableview for IOS

I am assuming you are doing this via Storyboard and since you haven't created your button via the Interface Builder, you need to check if the cell that is being re-used already has the button or not.

As per your current logic, you are creating a new button instance ever time the cell reappears.

I'd suggest the following:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

//following is required when using XIB but not needed when using Storyboard
/*
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
*/
//Reason:
//[1] When using XIB, dequeueReusableCellWithIdentifier does NOT create a cell so (cell == nil) condition occurs
//[2] When using Storyboard, dequeueReusableCellWithIdentifier DOES create a cell and so (cell == nil) condition never occurs

//check if cell is being reused by checking if the button already exists in it
UIButton *myButton = (UIButton *)[cell.contentView viewWithTag:100];

if (myButton == nil) {
myButton = [UIButton buttonWithType:UIButtonTypeCustom];
[myButton setFrame:CGRectMake(14.0,10.0,125.0,25.0)];
[myButton setTag:100]; //the tag is what helps in the first step
[myButton setTitle:@"Like" forState:UIControlStateNormal];
[myButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[myButton addTarget:self action:@selector(tapped:andEvent:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:myButton];

NSLog(@"Button created");
}
else {
NSLog(@"Button already created");
}

if ([likeState[indexPath.row] boolValue]) {
[myButton setTitle:@"Unlike" forState:UIControlStateNormal];
}
else {
[myButton setTitle:@"Like" forState:UIControlStateNormal];
}

return cell;
}

-(void)tapped:(UIButton *)sender andEvent:(UIEvent *)event
{
//get index
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:currentTouchPosition];

//toggle "like" status
if ([likeState[indexPath.row] boolValue]) {
[likeState replaceObjectAtIndex:indexPath.row withObject:@(0)];
[sender setTitle:@"Like" forState:UIControlStateNormal];
}
else {
[likeState replaceObjectAtIndex:indexPath.row withObject:@(1)];
[sender setTitle:@"Unlike" forState:UIControlStateNormal];
}
}

Don't reuse cell in UITableView

It's your decision of course, but it's a very bad idea. Unless you have less than 10 cells in your tableView and you are 100% sure there will be no more cells. Otherwise the app will crash on memory pressure pretty fast.

Just don't dequeue cells. Create new each time:

let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "CellReuseIdentifier")

Not recommended, but it's your decision after all.



A note about most recent swift versions:

'UITableViewCellStyle' has been renamed to 'UITableViewCell.CellStyle'

How do I handle reusable cells with custom tableView cells in this situation (changing cell background colour from other location in code not working)

You need to always set it — to what's appropriate.

if shouldSetBackgroundColor {
backgroundColor = .brown
} else {
backgroundColor = nil
}

Let's assume you initialize only 4 cells.
Then show 4 cells. Assume all have shouldSetBackgroundColor set to true. As a result you see all 4 cell's backgroundColor to brown. So far so good.

Now comes your 5th cell. If you don't set shouldSetBackgroundColor to false on the cell or don't have some logic to change the color of the backgroundColor then because the cell gets re-used, the backgroundColor won't change. It will remain set to brown...

How to reuse cells in a UITableView?

You create new variables called cell in the if statements. You are hiding the outer cell.

Use one cell variable.

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell

let identifier = cell_identifiers[indexPath.row][0] as! String

if ((cell_identifiers[indexPath.row][1] as! String) == "MYTURN" ) {
cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! GameViewCell
let match = self.myTurnMatches[indexPath.row - 4]
setupGameViewCellObject(match)
}

if ((cell_identifiers[indexPath.row][1] as! String) == "NOT" ) {
cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! FirstMenuTableViewCell
}
return cell
}

Not using reusable cell in UITableView with CollectionView in each cell

There are a few things to do that should get you up to speed.

First, uncomment the line that uses reusable cells and remove the line of code that creates the non-reusable cells. It is safe to use reusable cells here.

Second, in MyTableViewCell, set the dataSource for the collection view right after the super.awakeFromNib() call. You only need to set the dataSource once, but layoutSubviews() will potentially get called multiple times. It's not the right place to set the dataSource for your needs.

override func awakeFromNib() {
super.awakeFromNib()
categoryCollectionView.dataSource = self
}

I have removed the call to updateData() from awakeFromNib(), as you are already calling it at cell creation. You can also delete the layoutSubviews() override, but as a general rule, you should be careful to call super.layoutSubviews() when overriding it.

Lastly, the reason the posts seemed to re-appear in the wrong cells is that the posts array wasn't being emptied as the cells were reused. To fix this issue, add the following method to MyTableViewCell:

func resetCollectionView {
guard !posts.isEmpty else { return }
posts = []
categoryCollectionView.reloadData()
}

This method empties the array and reloads your collection view. Since there are no posts in the array now, the collection view will be empty until you call updateData again. Last step is to call that function in the cell's prepareForReuse method. Add the following to MyTableViewCell:

override func prepareForReuse() {
super.prepareForReuse()
resetCollectionView()
}

Let me know how it goes!

How cells are reused in UITableView?

cellForRowAt will return an existing cell object if there is one that is no more used by the table view. If that cell was a third one when it was presented, it has that new subview added. So to make it work as you expect, you would have to remove that subview in prepareForReuse which is called when that cell is being removed from view hierarchy and enqueued in the queue of reusable cells. That way when you call dequeueReusableCell, you will get a cell without the new subview.

However, in general, you do not want to add/remove subviews in cellForRowAt (unless there is no other option). Rather, if it is only a single specific view that you want to show in every third cell, add it in initializer and hide/unhide it in cellForRowAt (in your case, in objectForCell).

So declare a property:

let specialSubview = UIView()

Add it in init (or, if you use nib, then in awakeFromNib) and position it:

self.addSubview(specialSubview)
// autolayout constraints, configuring, etc.

And then in objectForCell:

var objectForCell : ObjectClass? {
didSet {
if let object = objectForCell {
someLabel.text = object.title
if object.id % 3 == 0 {
specialSubview.isHidden = false
} else {
specialSubview.isHidden = true
}
...


Related Topics



Leave a reply



Submit