Skip to content

Instantly share code, notes, and snippets.

@IanKeen
Last active July 10, 2019 22:02
Show Gist options
  • Save IanKeen/4ecbffea1e9d0c1bf1d6 to your computer and use it in GitHub Desktop.
Save IanKeen/4ecbffea1e9d0c1bf1d6 to your computer and use it in GitHub Desktop.
Small utility methods to simplify dealing with Reusable items i.e. table/collection view cells
//`UITableViewCell` and `UICollectionViewCell` are `Reusable` by defaut
//Use the extension method to dequeue an instance of the appropriate `Reusable`
class MyVC: UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
tableView
.registerReusable(FooCell.self)
.registerReusable(BarCell.self)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: FooCell = tableView.dequeueReusable(indexPath)
return cell
}
}
//Thats it!
protocol Reusable: class {
static var reuseIdentifier: String { get }
}
extension Reusable {
static var reuseIdentifier: String {
return String(self)
}
}
extension UITableViewCell: Reusable { }
extension UITableViewHeaderFooterView: Reusable { }
extension UICollectionViewCell: Reusable { }
extension UITableView {
//MARK: - Cells
func registerReusable(cellClass: Reusable.Type, fromNib: Bool = true) -> UITableView {
if (fromNib) {
let nib = UINib(nibName: cellClass.reuseIdentifier, bundle: nil)
self.registerNib(nib, forCellReuseIdentifier: cellClass.reuseIdentifier)
} else {
self.registerClass(cellClass, forCellReuseIdentifier: cellClass.reuseIdentifier)
}
return self
}
func dequeueReusable<T: UITableViewCell where T: Reusable>(indexPath: NSIndexPath) -> T {
return self.dequeueReusableCellWithIdentifier(T.reuseIdentifier, forIndexPath: indexPath) as! T
}
//MARK: - HeaderFooter
func registerReusableHeaderFooterView(headerFooterViewClass: Reusable.Type, fromNib: Bool = true) -> UITableView {
if (fromNib) {
let nib = UINib(nibName: headerFooterViewClass.reuseIdentifier, bundle: nil)
self.registerNib(nib, forHeaderFooterViewReuseIdentifier: headerFooterViewClass.reuseIdentifier)
} else {
self.registerClass(headerFooterViewClass, forHeaderFooterViewReuseIdentifier: headerFooterViewClass.reuseIdentifier)
}
return self
}
func dequeueReusableHeaderFooterView<T: UITableViewHeaderFooterView where T: Reusable>() -> T? {
return self.dequeueReusableHeaderFooterViewWithIdentifier(T.reuseIdentifier) as? T
}
}
extension UICollectionView {
//MARK: - Cells
func registerReusable(cellClass: Reusable.Type, fromNib: Bool = true) -> UICollectionView {
if (fromNib) {
let nib = UINib(nibName: cellClass.reuseIdentifier, bundle: nil)
self.registerNib(nib, forCellWithReuseIdentifier: cellClass.reuseIdentifier)
} else {
self.registerClass(cellClass, forCellWithReuseIdentifier: cellClass.reuseIdentifier)
}
return self
}
func dequeueReusable<T: UICollectionViewCell where T: Reusable>(indexPath: NSIndexPath) -> T {
return self.dequeueReusableCellWithReuseIdentifier(T.reuseIdentifier, forIndexPath: indexPath) as! T
}
}
@winkelsdorf
Copy link

winkelsdorf commented Oct 5, 2016

@IanKeen Sorry missed your notification. Guess the notification system's not working with Gists :(

You're very welcome. Yes, both approaches - with and T.Type are valid and have their benefits. Depends on your general code style. I just wanted to add and share my thoughts and improvements - glad you incorporated some of them :)

Here's the recent update for Swift 3, if anybody needs it:

import UIKit

public protocol Reusable: class {
    static var reuseIdentifier: String { get }
}

public extension Reusable {
    static var reuseIdentifier: String {
        return String(describing: self)
    }
}

extension UITableViewCell: Reusable { }
extension UITableViewHeaderFooterView: Reusable { }
extension UICollectionViewCell: Reusable { }

// MARK: - UITableViewCell
public extension UITableView {

    @discardableResult
    public func registerReusableClass(withClass cellClass: Reusable.Type) -> UITableView {
        register(cellClass, forCellReuseIdentifier: cellClass.reuseIdentifier)

        return self
    }

    @discardableResult
    public func registerReusableNib(withClass cellClass: Reusable.Type) -> UITableView {
        let nib = UINib(nibName: cellClass.reuseIdentifier, bundle: nil)
        register(nib, forCellReuseIdentifier: cellClass.reuseIdentifier)

        return self
    }

    public func dequeueReusableCell<T: UITableViewCell>(withClass cellClass: T.Type, for indexPath: IndexPath) -> T where T: Reusable {
        // swiftlint:disable:next force_cast
        return dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as! T
    }

}

// MARK: - UITableViewHeaderFooterView
public extension UITableView {

    @discardableResult
    public func registerReusableHeaderFooterView(withClass headerFooterViewClass: Reusable.Type, fromNib: Bool = false) -> UITableView {
        if fromNib {
            let nib = UINib(nibName: headerFooterViewClass.reuseIdentifier, bundle: nil)
            register(nib, forHeaderFooterViewReuseIdentifier: headerFooterViewClass.reuseIdentifier)
        } else {
            register(headerFooterViewClass, forHeaderFooterViewReuseIdentifier: headerFooterViewClass.reuseIdentifier)
        }

        return self
    }

    public func dequeueReusableHeaderFooterView<T: UITableViewHeaderFooterView>(withClass headerFooterViewClass: T.Type = T.self) -> T? where T: Reusable {
        return dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as? T
    }

}

// MARK: - UICollectionView
extension UICollectionView {

    @discardableResult
    public func registerReusable(withClass cellClass: Reusable.Type, fromNib: Bool = false) -> UICollectionView {
        if fromNib {
            let nib = UINib(nibName: cellClass.reuseIdentifier, bundle: nil)
            register(nib, forCellWithReuseIdentifier: cellClass.reuseIdentifier)
        } else {
            register(cellClass, forCellWithReuseIdentifier: cellClass.reuseIdentifier)
        }

        return self
    }

    public func dequeueReusableCell<T: UICollectionViewCell>(withClass cellClass: T.Type, for indexPath: IndexPath) -> T where T: Reusable {
        // swiftlint:disable:next force_cast
        return dequeueReusableCell(withReuseIdentifier: T.reuseIdentifier, for: indexPath) as! T
    }

}

@IanKeen
Copy link
Author

IanKeen commented Oct 22, 2016

Awesome! thanks for the updates 😄

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