Skip to content

Instantly share code, notes, and snippets.

@eMdOS
Last active October 15, 2021 12:29
Show Gist options
  • Save eMdOS/26c4da20eb46de74aacbee3e8d0d50e2 to your computer and use it in GitHub Desktop.
Save eMdOS/26c4da20eb46de74aacbee3e8d0d50e2 to your computer and use it in GitHub Desktop.
Reusable views and cell registration and dequeuing (for table views and collection views)

Reusable views and cell registration and dequeuing (for table views and collection views)

protocol NibLoadableView: class {
static var nibName: String { get }
}
extension NibLoadableView where Self: UIView {
static var nibName: String {
return String(describing: self)
}
}
protocol ReusableView: class {
static var reusableIdentifier: String { get }
}
extension ReusableView where Self: UIView {
static var reusableIdentifier: String {
return String(describing: self)
}
}
extension UICollectionView {
enum SupplementaryViewKind {
case header
case footer
var rawValue: String {
switch self {
case .header:
return UICollectionElementKindSectionHeader
case .footer:
return UICollectionElementKindSectionFooter
}
}
}
}
extension UICollectionView {
func register<T: UICollectionViewCell>(cell: T.Type) where T: ReusableView {
register(T.self, forCellWithReuseIdentifier: T.reusableIdentifier)
}
func register<T: UICollectionViewCell>(cell: T.Type) where T: ReusableView, T: NibLoadableView {
let nib = UINib(nibName: T.nibName, bundle: Bundle(for: T.self))
register(nib, forCellWithReuseIdentifier: T.reusableIdentifier)
}
func register<T: UICollectionReusableView>(view: T.Type, asSupplementaryViewKind kind: SupplementaryViewKind) where T: ReusableView {
register(T.self, forSupplementaryViewOfKind: kind.rawValue, withReuseIdentifier: T.reusableIdentifier)
}
func register<T: UICollectionReusableView>(view: T.Type, asSupplementaryViewKind kind: SupplementaryViewKind) where T: ReusableView, T: NibLoadableView {
let nib = UINib(nibName: T.nibName, bundle: Bundle(for: T.self))
register(nib, forSupplementaryViewOfKind: kind.rawValue, withReuseIdentifier: T.reusableIdentifier)
}
}
extension UICollectionView {
func dequeueReusableCell<T: UICollectionViewCell>(forIndexPath indexPath: IndexPath) -> T where T: ReusableView {
guard let cell = dequeueReusableCell(withReuseIdentifier: T.reusableIdentifier, for: indexPath) as? T else {
fatalError("Could not dequeue cell with identifier: \(T.reusableIdentifier)")
}
return cell
}
func dequeueReusableSupplementaryView<T: UICollectionReusableView>(ofKind kind: SupplementaryViewKind, forIndexPath indexPath: IndexPath) -> T where T: ReusableView {
guard let view = dequeueReusableSupplementaryView(ofKind: kind.rawValue, withReuseIdentifier: T.reusableIdentifier, for: indexPath) as? T else {
fatalError("Could not dequeue view with identifier: \(T.reusableIdentifier)")
}
return view
}
}
extension UICollectionViewLayout {
func register<T: UICollectionReusableView>(decorationView: T.Type) where T: ReusableView {
register(T.self, forDecorationViewOfKind: T.reusableIdentifier)
}
func register<T: UICollectionReusableView>(decorationView: T.Type) where T: ReusableView, T: NibLoadableView {
let nib = UINib(nibName: T.nibName, bundle: Bundle(for: T.self))
register(nib, forDecorationViewOfKind: T.reusableIdentifier)
}
}
extension UITableView {
func register<T: UITableViewCell>(cell: T.Type) where T: ReusableView {
register(T.self, forCellReuseIdentifier: T.reusableIdentifier)
}
func register<T: UITableViewCell>(cell: T.Type) where T: ReusableView, T: NibLoadableView {
let nib = UINib(nibName: T.nibName, bundle: Bundle(for: T.self))
register(nib, forCellReuseIdentifier: T.reusableIdentifier)
}
func register<T: UITableViewHeaderFooterView>(headerFooterView: T.Type) where T: ReusableView {
register(T.self, forHeaderFooterViewReuseIdentifier: T.reusableIdentifier)
}
func register<T: UITableViewHeaderFooterView>(headerFooterView: T.Type) where T: ReusableView, T: NibLoadableView {
let nib = UINib(nibName: T.nibName, bundle: Bundle(for: T.self))
register(nib, forHeaderFooterViewReuseIdentifier: T.reusableIdentifier)
}
}
extension UITableView {
func dequeueReusableCell<T: UITableViewCell>(forIndexPath indexPath: IndexPath) -> T where T: ReusableView {
guard let cell = dequeueReusableCell(withIdentifier: T.reusableIdentifier, for: indexPath) as? T else {
fatalError("Could not dequeue cell with identifier: \(T.reusableIdentifier)")
}
return cell
}
func dequeueReusableHeaderFooterView<T: UITableViewHeaderFooterView>() -> T where T: ReusableView {
guard let view = dequeueReusableHeaderFooterView(withIdentifier: T.reusableIdentifier) as? T else {
fatalError("Could not dequeue header/footer view with identifier: \(T.reusableIdentifier)")
}
return view
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment