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
How to Generate an Uiimage from Custom Text in Swift
Attach a PDF File to Email - Swift
Try Sample Avcam from Apple Found Error
Detect Screen Unlock Events in iOS Swift
Play Audio Through Upper (Phone Call) Speaker
Detecting If User Has in Call Status Bar
Uiwindow with Wrong Size When Using Landscape Orientation
How to Make Your Push Notification Open a Certain View Controller
Move Gmsmarker on Google Map Like Uber
Change the Listing Order of the View Controllers in Xcode Storyboard
Detect Tap on Calloutbubble in Mkannotationview
How to Detect an iOS App Installed or Upgraded
How to Restrict the iOS App Only for iPhone Excluding iPad
Custom Init of Uiviewcontroller from Storyboard
Swift How to Change Uialertcontroller's Title Color
Swift Images Change to Wrong Images While Scrolling After Async Image Loading to a Uitableviewcell