Skip to content

Instantly share code, notes, and snippets.

@SandeepAggarwal
Last active January 16, 2022 17:23
Show Gist options
  • Save SandeepAggarwal/1e6a1f10773e77f205a12186bb846c9a to your computer and use it in GitHub Desktop.
Save SandeepAggarwal/1e6a1f10773e77f205a12186bb846c9a to your computer and use it in GitHub Desktop.
UIKit table view cell reuse
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