Last active
July 10, 2019 22:02
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//`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! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
@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
}
}
Awesome! thanks for the updates 😄
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice Implementation.! (Y) +1