Reusable protocol

iOS, Swift, UIKit

Easy UITableView/UICollectionView cell registering/dequeuing with the power of protocols and extensions

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 } }