Skip to content

Instantly share code, notes, and snippets.

@gabrieloc
Last active August 28, 2019 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gabrieloc/8a9bf1f0d0ec882701d313af44f484a9 to your computer and use it in GitHub Desktop.
Save gabrieloc/8a9bf1f0d0ec882701d313af44f484a9 to your computer and use it in GitHub Desktop.
Typed UITableViewCell/UICollectionViewCell registration and dequeuing
//
// Reusable.swift
// Reusable
//
// Copyright (c) <2018>, Gabriel O'Flaherty-Chan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. All advertising materials mentioning features or use of this software
// must display the following acknowledgement:
// This product includes software developed by skysent.
// 4. Neither the name of the skysent nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY skysent ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL skysent BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
import UIKit
public protocol Reusable {
}
extension UICollectionReusableView: Reusable {
}
extension UITableViewCell: Reusable {
}
extension UICollectionView {
public typealias Cell = UICollectionReusableView
public enum CellType {
case cell, header, footer
var kind: String? {
switch self {
case .header:
return UICollectionView.elementKindSectionHeader
case .footer:
return UICollectionView.elementKindSectionFooter
default:
return nil
}
}
}
public func register(_ type: CellType, _ cellClass: Cell.Type) {
let identifier = String(describing: cellClass)
switch type {
case .cell:
if let nib = cellClass.nib {
register(nib, forCellWithReuseIdentifier: identifier)
} else {
register(cellClass, forCellWithReuseIdentifier: identifier)
}
default:
let kind = type.kind!
if let nib = cellClass.nib {
register(nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: identifier)
} else {
register(cellClass, forSupplementaryViewOfKind: kind, withReuseIdentifier: identifier)
}
}
}
public func dequeue<T>(_ type: CellType = .cell, for indexPath: IndexPath) -> T? where T: Reusable {
let identifier = String(describing: T.self)
switch type {
case .cell:
return dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as? T
default:
return dequeueReusableSupplementaryView(ofKind: type.kind!, withReuseIdentifier: identifier, for: indexPath) as? T
}
}
}
public protocol ReusableHeader {
}
extension UITableViewHeaderFooterView: ReusableHeader {
}
extension UITableView {
public typealias Cell = UITableViewCell
public func registerHeader(_ cellClass: UITableViewHeaderFooterView.Type) {
let identifier = String(describing: cellClass)
if let nib = cellClass.nib {
register(nib, forHeaderFooterViewReuseIdentifier: identifier)
} else {
register(cellClass, forHeaderFooterViewReuseIdentifier: identifier)
}
}
public func register(_ types: Cell.Type...) {
types.forEach { cellClass in
let identifier = String(describing: cellClass)
if let nib = cellClass.nib {
register(nib, forCellReuseIdentifier: identifier)
} else {
register(cellClass, forCellReuseIdentifier: identifier)
}
}
}
public func dequeueReusableCell<T>(for indexPath: IndexPath) -> T? where T: Reusable {
return dequeueReusableCell(withIdentifier: String(describing: T.self), for: indexPath) as? T
}
public func dequeueReusableCell<T: Reusable>(for indexPath: IndexPath, type: T.Type) -> T? {
return dequeueReusableCell(withIdentifier: String(describing: type), for: indexPath) as? T
}
public func dequeueHeader<T: ReusableHeader>() -> T? {
return dequeueReusableHeaderFooterView(withIdentifier: String(describing: T.self)) as? T
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment