Reusable protocol
iOS, Swift, UIKit
Create a reusable protocol
swift
protocol Reusable {
static var reuseIdentifier: String { get }
}
UICollectionView
swift
extension Reusable where Self: UICollectionViewCell {
static var reuseIdentifier: String {
return String(describing: type(of: self))
}
}
extension Reusable where Self: UICollectionReusableView {
static var reuseIdentifier: String {
return String(describing: type(of: self))
}
}
Registration:
swift
extension UICollectionView {
func registerCell<C: UICollectionViewCell & Reusable>(_ cellType: C.Type) {
register(
C.self,
forCellWithReuseIdentifier: cellType.reuseIdentifier
)
}
func registerReusableView<V: UICollectionReusableView & Reusable>(_ viewType: V.Type) {
register(
V.self,
forSupplementaryViewOfKind: V.reuseIdentifier,
withReuseIdentifier: viewType.reuseIdentifier
)
}
func registerHeaderView<V: UICollectionReusableView & Reusable>(_ viewType: V.Type) {
register(
V.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: viewType.reuseIdentifier
)
}
func registerFooterView<V: UICollectionReusableView & Reusable>(_ viewType: V.Type) {
register(
V.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
withReuseIdentifier: viewType.reuseIdentifier
)
}
}
Dequeuing:
swift
extension UICollectionView {
func dequeueReusableCell<C: UICollectionViewCell & Reusable>(
_ cellType: C.Type,
for indexPath: IndexPath
) -> C {
guard let cell = dequeueReusableCell(
withReuseIdentifier: cellType.reuseIdentifier,
for: indexPath) as? C
else {
fatalError("Unable to dequeue reusable cell of type `\(cellType)`")
}
return cell
}
func dequeueReusableHeaderView<V: UICollectionReusableView & Reusable>(
_ viewType: V.Type,
for indexPath: IndexPath
) -> V {
guard let view = dequeueReusableSupplementaryView(
ofKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: viewType.reuseIdentifier,
for: indexPath) as? V
else {
fatalError("Unable to dequeue reusable view of type `\(viewType)`")
}
return view
}
func dequeueReusableView<V: UICollectionReusableView & Reusable>(
_ viewType: V.Type,
for indexPath: IndexPath
) -> V {
guard let view = dequeueReusableSupplementaryView(
ofKind: V.reuseIdentifier,
withReuseIdentifier: viewType.reuseIdentifier,
for: indexPath) as? V
else {
fatalError("Unable to dequeue reusable view of type `\(viewType)`")
}
return view
}
func dequeueReusableFooterView<V: UICollectionReusableView & Reusable>(
_ viewType: V.Type,
for indexPath: IndexPath
) -> V {
guard let view = dequeueReusableSupplementaryView(
ofKind: UICollectionView.elementKindSectionFooter,
withReuseIdentifier: viewType.reuseIdentifier,
for: indexPath) as? V
else {
fatalError("Unable to dequeue reusable view of type `\(viewType)`")
}
return view
}
}
UITableView
swift
extension Reusable where Self: UITableViewCell {
static var reuseIdentifier: String {
return String(describing: type(of: self))
}
}
extension Reusable where Self: UITableViewHeaderFooterView {
static var reuseIdentifier: String {
return String(describing: type(of: self))
}
}
Registration:
swift
extension UITableView {
func registerCell<C: UITableViewCell & Reusable>(_ cellType: C.Type) {
register(C.self, forCellReuseIdentifier: C.reuseIdentifier)
}
func registerHeaderFooterView<V: UITableViewHeaderFooterView & Reusable>(_ viewType: V.Type) {
register(V.self, forHeaderFooterViewReuseIdentifier: V.reuseIdentifier)
}
}
Dequeuing:
swift
extension UITableView {
func dequeueReusableCell<C: UITableViewCell & Reusable>(
_ cellType: C.Type,
cellStyle style: UITableViewCell.CellStyle = .default
) -> C {
guard let cell = dequeueReusableCell(withIdentifier: cellType.reuseIdentifier) as? C else {
fatalError("Unable to dequeue reusable cell of type `\(cellType)`")
}
return cell
}
func dequeueReusableHeaderFooterView<V: UITableViewHeaderFooterView & Reusable>(_ viewType: V.Type) -> V? {
guard let view = dequeueReusableHeaderFooterView(withIdentifier: viewType.reuseIdentifier) as? V else {
fatalError("Unable to dequeue reusable view of type `\(viewType)`")
}
return view
}
}