Skip to content

Instantly share code, notes, and snippets.

@marty-suzuki
Created October 30, 2019 05:07
Show Gist options
  • Save marty-suzuki/161564002b05cde13cd98fb0f773be3e to your computer and use it in GitHub Desktop.
Save marty-suzuki/161564002b05cde13cd98fb0f773be3e to your computer and use it in GitHub Desktop.
struct Generic<T> {
fileprivate let base: T
}
extension Generic where T == UICollectionView {
fileprivate init(_ base: UICollectionView) {
self.base = base
}
func register<View: UIView & Reusable>(_: View.Type) {
let identifier = String(describing: CollectionViewCell<View>.self)
base.register(CollectionViewCell<View>.self, forCellWithReuseIdentifier: identifier)
}
func dequeue<View: UIView & Reusable>(_: View.Type, for indexPath: IndexPath) -> CollectionViewCell<View> {
let identifier = String(describing: CollectionViewCell<View>.self)
return base.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! CollectionViewCell<View>
}
}
extension UICollectionView {
var generic: Generic<UICollectionView> {
return Generic(self)
}
}
extension Generic where T == UITableView {
fileprivate init(_ base: UITableView) {
self.base = base
}
func register<View: UIView & Reusable>(_: View.Type) {
let identifier = String(describing: TableViewCell<View>.self)
base.register(TableViewCell<View>.self, forCellReuseIdentifier: identifier)
}
func dequeue<View: UIView & Reusable>(_: View.Type, for indexPath: IndexPath) -> TableViewCell<View> {
let identifier = String(describing: TableViewCell<View>.self)
return base.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as! TableViewCell<View>
}
}
extension UITableView {
var generic: Generic<UITableView> {
return Generic(self)
}
}
// MARK: - Protocols
protocol ViewInitializable: AnyObject {
init(frame: CGRect)
}
protocol Reusable: AnyObject {
static func make() -> Self
func prepareForReuse()
}
extension Reusable where Self: ViewInitializable {
static func make() -> Self {
return .init(frame: .zero)
}
}
extension Reusable where Self: Nibable {
static func make() -> Self {
return makeFromNib()
}
}
protocol Nibable: AnyObject {
static var nibName: String { get }
static var nib: UINib { get }
static func makeFromNib() -> Self
}
extension Nibable where Self: UIView {
static var nibName: String {
return String(describing: self)
}
static var nib: UINib {
return UINib(nibName: String(describing: self), bundle: nil)
}
static func makeFromNib() -> Self {
return nib.instantiate(withOwner: nil, options: nil).first as! Self
}
}
typealias ReusableView = UIView & Reusable & ViewInitializable
typealias ReusableNibView = UIView & Reusable & Nibable
// MARK: - Cells
final class CollectionViewCell<View: UIView & Reusable>: UICollectionViewCell {
let view = View.make()
override init(frame: CGRect) {
super.init(frame: frame)
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(view)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(view)
}
override func prepareForReuse() {
super.prepareForReuse()
view.prepareForReuse()
}
}
final class TableViewCell<View: UIView & Reusable>: UITableViewCell {
let view = View.make()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(view)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(view)
}
override func prepareForReuse() {
super.prepareForReuse()
view.prepareForReuse()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment