Skip to content

Instantly share code, notes, and snippets.

@tapi
Created April 4, 2016 16:38
Show Gist options
  • Save tapi/60a6ee1cbfeabd12180ad88d9714591f to your computer and use it in GitHub Desktop.
Save tapi/60a6ee1cbfeabd12180ad88d9714591f to your computer and use it in GitHub Desktop.
Typed UITableView & UICollectionView Dequeuing in Swift
import UIKit
extension UICollectionReusableView {
/// The default implementation of `defaultIdentifier()` uses `NSStringFromClass(class)` rather than `String(class)` so that the module name is includded.
/// The hope being that this makes collisions unlikely making it unnnecessary to provide your own implementations.
public class func defaultIdentifier() -> String {
return NSStringFromClass(self)
}
}
// MARK: - Cell Registration
public extension UICollectionView {
public func register<T: UICollectionViewCell>(cellClass `class`: T.Type) {
registerClass(`class`, forCellWithReuseIdentifier: `class`.defaultIdentifier())
}
public func register<T: UICollectionViewCell>(nib: UINib, forClass `class`: T.Type) {
registerNib(nib, forCellWithReuseIdentifier: `class`.defaultIdentifier())
}
/**
Dequeue a Reusable Cell in a way that provides type information.
This call will raise a fatal error if the cell was not registered with `defaultIdentifier()` this behaviour is not particularily different from the method which it is covering,
`dequeueReusableCellWithReuseIdentifier` which will raise an NSInternalInconsistency Exception because the cell was not registered with the corrrect identifier. If you are going to use this
dequeue method it is recomended that you use `register<T: UICollectionViewCell>(cellClass: T.Type)` or `register<T: UICollectionViewCell>(nib: UINib, forClass: T.Type)` for registration.
- parameter `class`: The class whose type you are dequeing.
- parameter indexPath: The index path of the cell you want to dequeue.
- returns: Returns a cell of the type requested.
*/
public func dequeueReusableCell<T: UICollectionViewCell>(withClass `class`: T.Type, forIndexPath indexPath: NSIndexPath) -> T {
guard let cell = dequeueReusableCellWithReuseIdentifier(`class`.defaultIdentifier(), forIndexPath: indexPath) as? T else {
fatalError("Error: cell with identifier: \(`class`.defaultIdentifier()) for index path: \(indexPath) is not \(T.self)")
}
return cell
}
}
// MARK: - Supplementary View Registration
public extension UICollectionView {
public func register<T: UICollectionReusableView>(viewClass `class`: T.Type, forSupplementaryViewOfKind kind: String) {
registerClass(`class`, forSupplementaryViewOfKind: kind, withReuseIdentifier: `class`.defaultIdentifier())
}
public func register<T: UICollectionReusableView>(nib: UINib, forSupplementaryViewOfKind kind: String, withClass `class`: T.Type) {
registerNib(nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: `class`.defaultIdentifier())
}
/**
Dequeue a Supplementary View in a way that provides type information.
This call will raise a fatal error if the view was not registered with `defaultIdentifier()` this behaviour is not particularily different from the method which it is covering,
`dequeueReusableSupplementaryViewOfKind` which will raise an NSInternalInconsistency Exception because the cell was not registered with the corrrect identifier. If you are going to use this
dequeue method it is recomended that you use `register<T: UICollectionReusableView>(viewClass: T.Type, forSupplementaryViewOfKind: String)` or
`register<T: UICollectionReusableView>(nib: UINib, forSupplementaryViewOfKind: String, withClass: T.Type)` for registration.
- parameter `class`: The class whose type you are dequeing.
- parameter kind: The supplementary view Kind you are dequeing.
- parameter indexPath: The index path of the cell you want to dequeue.
- returns: Returns a view of the type requested.
*/
public func dequeueReusableSupplementaryView<T: UICollectionReusableView>(withClass `class`: T.Type, ofKind kind: String, forIndexPath indexPath: NSIndexPath) -> T {
guard let supplement = dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: `class`.defaultIdentifier(), forIndexPath: indexPath) as? T else {
fatalError("Error: supplementary view with identifier: \(`class`.defaultIdentifier()) for index path: \(indexPath) is not \(T.self)")
}
return supplement
}
}
import UIKit
extension UITableViewCell {
/// The default implementation of `defaultIdentifier()` uses `NSStringFromClass(class)` rather than `String(class)` so that the module name is includded.
/// The hope being that this makes collisions unlikely making it unnnecessary to provide your own implementations.
public class func defaultIdentifier() -> String {
return NSStringFromClass(self)
}
}
extension UITableViewHeaderFooterView {
/// The default implementation of `defaultIdentifier()` uses `NSStringFromClass(class)` rather than `String(class)` so that the module name is includded.
/// The hope being that this makes collisions unlikely making it unnnecessary to provide your own implementations.
public class func defaultIdentifier() -> String {
return NSStringFromClass(self)
}
}
// MARK: - Cell Registration
extension UITableView {
public func register<T: UITableViewCell>(cellClass `class`: T.Type) {
registerClass(`class`, forCellReuseIdentifier: `class`.defaultIdentifier())
}
public func register<T: UITableViewCell>(nib: UINib, forClass `class`: T.Type) {
registerNib(nib, forCellReuseIdentifier: `class`.defaultIdentifier())
}
/**
Dequeue a Reusable Cell in a way that provides type information.
If you are going to use this dequeue method it is recomended that you use `register<T: UITableViewCell>(cellClass: T.Type)` or
`register<T: UITableViewCell>(nib: UINib, forClass: T.Type)` for registration.
- parameter `class`: The class whose type you are dequeing.
- returns: Returns a view of the type requested if it was registered, `nil` otherwise.
*/
public func dequeueReusableCell<T: UITableViewCell>(withClass `class`: T.Type) -> T? {
return dequeueReusableCellWithIdentifier(`class`.defaultIdentifier()) as? T
}
/**
Dequeue a Reusable Cell in a way that provides type information.
This call will raise a fatal error if the cell was not registered with `defaultIdentifier()` this behaviour is not particularily different from the method which it is covering,
`dequeueReusableCellWithIdentifier` which will raise an NSInternalInconsistency Exception because the cell was not registered with the corrrect identifier or at all. If you are going to use this
dequeue method it is recomended that you use `register<T: UITableViewCell>(cellClass: T.Type)` or `register<T: UITableViewCell>(nib: UINib, forClass: T.Type)` for registration.
- parameter `class`: The class whose type you are dequeing.
- parameter indexPath: The index path of the cell you want to dequeue.
- returns: Returns a cell of the type requested.
*/
public func dequeueReusableCell<T: UITableViewCell>(withClass `class`: T.Type, forIndexPath indexPath: NSIndexPath) -> T {
guard let cell = dequeueReusableCellWithIdentifier(`class`.defaultIdentifier(), forIndexPath: indexPath) as? T else {
fatalError("Error: cell with identifier: \(`class`.defaultIdentifier()) for index path: \(indexPath) is not \(T.self)")
}
return cell
}
}
// MARK: - Supplementary View Registration
extension UITableView {
public func register<T: UITableViewHeaderFooterView>(headerFooterClass `class`: T.Type) {
registerClass(`class`, forHeaderFooterViewReuseIdentifier: `class`.defaultIdentifier())
}
public func register<T: UITableViewHeaderFooterView>(nib: UINib, forHeaderFooterClass `class`: T.Type) {
registerNib(nib, forHeaderFooterViewReuseIdentifier: `class`.defaultIdentifier())
}
/**
Dequeue a Header/Footer View in a way that provides type information.
If you are going to use this dequeue method it is recomended that you use `register<T: UITableViewHeaderFooterView>(headerFooterClass `class`: T.Type)` or
`register<T: UITableViewHeaderFooterView>(nib: UINib, forHeaderFooterClass `class`: T.Type)` for registration.
- parameter `class`: The class whose type you are dequeing.
- returns: Returns a view of the type requested if it was registered, `nil` otherwise.
*/
public func dequeueResuableHeaderFooterView<T: UITableViewHeaderFooterView>(withClass `class`: T.Type) -> T? {
return dequeueReusableHeaderFooterViewWithIdentifier(`class`.defaultIdentifier()) as? T
}
}
@tapi
Copy link
Author

tapi commented Apr 11, 2016

Zev Eisenberg posted that you can use

    public class func defaultIdentifier() -> String {
        return "\(self)"
    }

To get a nice readable nav for your default identifiers, even from generic cells.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment