Last active
January 16, 2022 17:23
-
-
Save SandeepAggarwal/1e6a1f10773e77f205a12186bb846c9a to your computer and use it in GitHub Desktop.
UIKit table view cell reuse
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import PlaygroundSupport | |
class Cell: UITableViewCell { | |
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { | |
super.init(style: style, reuseIdentifier: reuseIdentifier) | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func prepareForReuse() { | |
super.prepareForReuse() | |
} | |
} | |
class IndexPathCell { | |
var indexPath: IndexPath | |
let cell: UITableViewCell | |
init(indexPath: IndexPath, cell: UITableViewCell) { | |
self.indexPath = indexPath | |
self.cell = cell | |
} | |
} | |
class MyTableView: UITableView { | |
var identifierIndexPathCells = [String: [IndexPathCell]]() | |
var identifierClass = [String: AnyClass]() | |
func dequeueMyReusableCell(withIdentifier identifier: String, for indexPath: IndexPath) -> UITableViewCell { | |
var indexPathCells = identifierIndexPathCells[identifier] ?? [] | |
defer { identifierIndexPathCells[identifier] = indexPathCells } | |
let visibleIndexPaths = indexPathsForVisibleRows ?? [] | |
let scrollingDown = indexPath.row > (indexPathCells.last?.indexPath.row ?? -1) | |
if scrollingDown { | |
if let indexPathCell = indexPathCells.first, (!visibleIndexPaths.contains(indexPathCell.indexPath) || indexPathCell.cell.isHidden) { | |
indexPathCells.removeFirst() | |
indexPathCells.append(indexPathCell) | |
indexPathCell.indexPath = indexPath | |
indexPathCell.cell.prepareForReuse() | |
return indexPathCell.cell | |
} | |
} else { | |
if let indexPathCell = indexPathCells.last, (!visibleIndexPaths.contains(indexPathCell.indexPath) || indexPathCell.cell.isHidden) { | |
indexPathCells.removeLast() | |
indexPathCells.insert(indexPathCell, at: 0) | |
indexPathCell.indexPath = indexPath | |
indexPathCell.cell.prepareForReuse() | |
return indexPathCell.cell | |
} | |
} | |
guard let aClass = identifierClass[identifier] else { | |
preconditionFailure("cell not registered") | |
} | |
guard let CellClass = aClass as? UITableViewCell.Type else { | |
preconditionFailure("classs not of UITableViewCell type") | |
} | |
let cell = CellClass.init(style: .default, reuseIdentifier: identifier) | |
let indexPathCell = IndexPathCell(indexPath: indexPath, cell: cell) | |
if scrollingDown { | |
indexPathCells.append(indexPathCell) | |
} else { | |
indexPathCells.insert(indexPathCell, at: 0) | |
} | |
return cell | |
} | |
func registerMy(_ cellClass: AnyClass?, forCellReuseIdentifier identifier: String) { | |
identifierClass[identifier] = cellClass | |
} | |
} | |
class DataSource: NSObject, UITableViewDataSource { | |
private static let identifier = "cell" | |
init(tableView: UITableView) { | |
super.init() | |
(tableView as! MyTableView).registerMy(Cell.self, forCellReuseIdentifier: DataSource.identifier) | |
} | |
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
return 100 | |
} | |
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
let cell = (tableView as! MyTableView).dequeueMyReusableCell(withIdentifier: DataSource.identifier, for: indexPath) | |
cell.textLabel?.text = "\(indexPath.row + 1)" | |
return cell | |
} | |
} | |
let tableView = MyTableView(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 400))) | |
let dataSource = DataSource(tableView: tableView) | |
tableView.dataSource = dataSource | |
PlaygroundPage.current.setLiveView(tableView) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment