Skip to content

Instantly share code, notes, and snippets.

@gabrieloc
Last active August 29, 2019 15:26
Show Gist options
  • Save gabrieloc/f305a2e20e8be1f1a6fb9533ba937040 to your computer and use it in GitHub Desktop.
Save gabrieloc/f305a2e20e8be1f1a6fb9533ba937040 to your computer and use it in GitHub Desktop.

Revisions

  1. gabrieloc revised this gist Aug 29, 2019. 1 changed file with 0 additions and 133 deletions.
    133 changes: 0 additions & 133 deletions Reusable.swift
    Original file line number Diff line number Diff line change
    @@ -1,133 +0,0 @@
    //
    // 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

    protocol Reusable {
    }

    extension UICollectionReusableView: Reusable {
    }

    extension UITableViewCell: Reusable {
    }

    extension UICollectionView {
    typealias Cell = UICollectionReusableView

    enum CellType {
    case cell, header, footer

    var kind: String? {
    switch self {
    case .header:
    return UICollectionView.elementKindSectionHeader
    case .footer:
    return UICollectionView.elementKindSectionFooter
    default:
    return nil
    }
    }
    }

    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)
    }
    }
    }

    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
    }
    }
    }

    protocol ReusableHeader {
    }

    extension UITableViewHeaderFooterView: ReusableHeader {
    }

    extension UITableView {
    typealias Cell = UITableViewCell

    func registerHeader(_ cellClass: UITableViewHeaderFooterView.Type) {
    let identifier = String(describing: cellClass)
    if let nib = cellClass.nib {
    register(nib, forHeaderFooterViewReuseIdentifier: identifier)
    } else {
    register(cellClass, forHeaderFooterViewReuseIdentifier: identifier)
    }
    }

    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)
    }
    }
    }

    func dequeueReusableCell<T>(for indexPath: IndexPath) -> T? where T: Reusable {
    return dequeueReusableCell(withIdentifier: String(describing: T.self), for: indexPath) as? T
    }

    func dequeueReusableCell<T: Reusable>(for indexPath: IndexPath, type: T.Type) -> T? {
    return dequeueReusableCell(withIdentifier: String(describing: type), for: indexPath) as? T
    }

    func dequeueHeader<T: ReusableHeader>() -> T? {
    return dequeueReusableHeaderFooterView(withIdentifier: String(describing: T.self)) as? T
    }
    }
  2. gabrieloc revised this gist Aug 29, 2019. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions NibLoadable.swift
    Original file line number Diff line number Diff line change
    @@ -34,18 +34,18 @@

    import UIKit

    protocol NibLoadable { }
    public protocol NibLoadable { }
    extension UIView: NibLoadable { }
    extension NibLoadable where Self: UIView {

    static var nib: UINib? {
    public static var nib: UINib? {
    let bundle = Bundle(for: self)
    let resource = String(describing: self)
    guard bundle.path(forResource: resource, ofType: "nib") != nil else {
    return nil
    }

    return UINib(nibName: resource, bundle: nil)
    return UINib(nibName: resource, bundle: bundle)
    }

    static var reuseIdentifier: String {
    @@ -55,16 +55,16 @@ extension NibLoadable where Self: UIView {

    /* Only use for final classes, as this find a nib with a name cooresponding to class name
    */
    var viewFromNib: UIView? {
    public var viewFromNib: UIView? {
    return type(of: self).viewFromNib(owner: self)
    }

    static func viewFromNib(owner: Any?) -> UIView? {
    public static func viewFromNib(owner: Any?) -> UIView? {
    let view = nib?.instantiate(withOwner: owner, options: nil).first
    return view as? UIView
    }

    static var viewFromNib: Self? {
    public static var viewFromNib: Self? {
    let view = nib?.instantiate(withOwner: nil, options: nil).first
    return view as? Self
    }
  3. gabrieloc revised this gist Aug 26, 2019. No changes.
  4. gabrieloc created this gist Aug 26, 2019.
    71 changes: 71 additions & 0 deletions NibLoadable.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    //
    // NibLoadable.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

    protocol NibLoadable { }
    extension UIView: NibLoadable { }
    extension NibLoadable where Self: UIView {

    static var nib: UINib? {
    let bundle = Bundle(for: self)
    let resource = String(describing: self)
    guard bundle.path(forResource: resource, ofType: "nib") != nil else {
    return nil
    }

    return UINib(nibName: resource, bundle: nil)
    }

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


    /* Only use for final classes, as this find a nib with a name cooresponding to class name
    */
    var viewFromNib: UIView? {
    return type(of: self).viewFromNib(owner: self)
    }

    static func viewFromNib(owner: Any?) -> UIView? {
    let view = nib?.instantiate(withOwner: owner, options: nil).first
    return view as? UIView
    }

    static var viewFromNib: Self? {
    let view = nib?.instantiate(withOwner: nil, options: nil).first
    return view as? Self
    }
    }
    133 changes: 133 additions & 0 deletions Reusable.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,133 @@
    //
    // 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

    protocol Reusable {
    }

    extension UICollectionReusableView: Reusable {
    }

    extension UITableViewCell: Reusable {
    }

    extension UICollectionView {
    typealias Cell = UICollectionReusableView

    enum CellType {
    case cell, header, footer

    var kind: String? {
    switch self {
    case .header:
    return UICollectionView.elementKindSectionHeader
    case .footer:
    return UICollectionView.elementKindSectionFooter
    default:
    return nil
    }
    }
    }

    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)
    }
    }
    }

    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
    }
    }
    }

    protocol ReusableHeader {
    }

    extension UITableViewHeaderFooterView: ReusableHeader {
    }

    extension UITableView {
    typealias Cell = UITableViewCell

    func registerHeader(_ cellClass: UITableViewHeaderFooterView.Type) {
    let identifier = String(describing: cellClass)
    if let nib = cellClass.nib {
    register(nib, forHeaderFooterViewReuseIdentifier: identifier)
    } else {
    register(cellClass, forHeaderFooterViewReuseIdentifier: identifier)
    }
    }

    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)
    }
    }
    }

    func dequeueReusableCell<T>(for indexPath: IndexPath) -> T? where T: Reusable {
    return dequeueReusableCell(withIdentifier: String(describing: T.self), for: indexPath) as? T
    }

    func dequeueReusableCell<T: Reusable>(for indexPath: IndexPath, type: T.Type) -> T? {
    return dequeueReusableCell(withIdentifier: String(describing: type), for: indexPath) as? T
    }

    func dequeueHeader<T: ReusableHeader>() -> T? {
    return dequeueReusableHeaderFooterView(withIdentifier: String(describing: T.self)) as? T
    }
    }