From 23f92b53469e4eaf869644d46e9119975f6b4d7f Mon Sep 17 00:00:00 2001 From: apptekstudios Date: Sat, 4 Aug 2018 12:11:26 +1000 Subject: [PATCH 1/5] =?UTF-8?q?Implement=20=E2=80=98AutoRegistering?= =?UTF-8?q?=E2=80=99=20Protocol=20-=20Updated=20examples=20-=20Updated=20d?= =?UTF-8?q?ocs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyColorSquareCell.swift | 2 +- .../CollectionViewController.swift | 6 +- .../MyAutoRegisterTableViewHeader.swift | 32 +++ .../MyAutoRegisterTableViewHeader.xib | 56 +++++ ...ableView.swift => MyTableViewHeader.swift} | 4 +- ...derTableView.xib => MyTableViewHeader.xib} | 6 +- .../TableViewCells/MyXIBInfoCell.swift | 2 +- .../TableViewController.swift | 46 ++-- .../ReusableDemo.xcodeproj/project.pbxproj | 24 +- README.md | 12 +- Sources/View/Reusable.swift | 7 + Sources/View/UICollectionView+Reusable.swift | 207 +++++++++++++++++- Sources/View/UITableView+Reusable.swift | 145 +++++++++++- 13 files changed, 502 insertions(+), 47 deletions(-) create mode 100755 Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.swift create mode 100755 Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.xib rename Example/ReusableDemo iOS/TableViewCells/{MyHeaderTableView.swift => MyTableViewHeader.swift} (84%) rename Example/ReusableDemo iOS/TableViewCells/{MyHeaderTableView.xib => MyTableViewHeader.xib} (91%) diff --git a/Example/ReusableDemo iOS/CollectionViewCells/MyColorSquareCell.swift b/Example/ReusableDemo iOS/CollectionViewCells/MyColorSquareCell.swift index 9e4c98d..7173dca 100644 --- a/Example/ReusableDemo iOS/CollectionViewCells/MyColorSquareCell.swift +++ b/Example/ReusableDemo iOS/CollectionViewCells/MyColorSquareCell.swift @@ -18,7 +18,7 @@ import Reusable * This view is NOT loaded from a NIB (but defined entierly by code), * that's why it's not annotated as `NibLoadable` but only `Reusable` */ -final class MyColorSquareCell: UICollectionViewCell, Reusable { +final class MyColorSquareCell: UICollectionViewCell, Reusable, AutoRegistering { private lazy var colorView: UIView = { let colorView = UIView() colorView.autoresizingMask = [.flexibleWidth, .flexibleHeight] diff --git a/Example/ReusableDemo iOS/CollectionViewController.swift b/Example/ReusableDemo iOS/CollectionViewController.swift index 1f4cdb8..2985f75 100644 --- a/Example/ReusableDemo iOS/CollectionViewController.swift +++ b/Example/ReusableDemo iOS/CollectionViewController.swift @@ -15,8 +15,12 @@ final class CollectionViewController: UICollectionViewController { guard let collectionView = self.collectionView else { return } // Register cell classes - collectionView.register(cellType: MyColorSquareCell.self) collectionView.register(cellType: MyXIBIndexSquaceCell.self) + + /* Since MyColorSquareCell is marked as conforming to AutoRegistering, + there's no need to register this type ahead of time */ + //collectionView.register(cellType: MyColorSquareCell.self) + // No need to register this one, the UIStoryboard already auto-register its cells // self.collectionView.registerReusableCell(MyStoryBoardIndexPathCell) diff --git a/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.swift b/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.swift new file mode 100755 index 0000000..9854d7e --- /dev/null +++ b/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.swift @@ -0,0 +1,32 @@ +// +// MyAutoRegisterHeaderTableView.swift +// ReusableDemo +// +// Created by TJB on 07/08/18. +// Copyright © 2018 ApptekStudios. All rights reserved. +// + +import UIKit +import Reusable + +/** + * This view is loaded from a NIB, and is the XIB file's + * root view (and not the File's Owner). => it is `NibLoadable` + * + * It is also reusable and has a `reuseIdentifier` (as it's a TableViewHeaderFooterView + * and it uses the TableView recycling mechanism) => it is `Reusable` + * + * That's why it's annotated with the `NibReusable` typealias, + * Which in fact is just a convenience typealias that combines + * `NibLoadable` & `Reusable` protocols. + */ +final class MyAutoRegisterTableViewHeader: UITableViewHeaderFooterView, NibReusable, AutoRegistering { + + @IBOutlet private weak var titleLabel: UILabel! + + static let height: CGFloat = 55 + + func fillForSection(_ section: Int) { + self.titleLabel.text = "Header Section #\(section)" + } +} diff --git a/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.xib b/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.xib new file mode 100755 index 0000000..3f243f7 --- /dev/null +++ b/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.xib @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/ReusableDemo iOS/TableViewCells/MyHeaderTableView.swift b/Example/ReusableDemo iOS/TableViewCells/MyTableViewHeader.swift similarity index 84% rename from Example/ReusableDemo iOS/TableViewCells/MyHeaderTableView.swift rename to Example/ReusableDemo iOS/TableViewCells/MyTableViewHeader.swift index e2a35dd..861119b 100755 --- a/Example/ReusableDemo iOS/TableViewCells/MyHeaderTableView.swift +++ b/Example/ReusableDemo iOS/TableViewCells/MyTableViewHeader.swift @@ -15,7 +15,7 @@ import Reusable * * That's why it's annotated with the `NibOwnerLoadable` protocol. */ -final class MyHeaderTableView: UIView, NibOwnerLoadable { +final class MyTableViewHeader: UIView, NibOwnerLoadable { @IBOutlet private weak var titleLabel: UILabel! static let height: CGFloat = 55 @@ -30,6 +30,6 @@ final class MyHeaderTableView: UIView, NibOwnerLoadable { } func fillForSection(_ section: Int) { - self.titleLabel.text = "Header Section #\(section)" + self.titleLabel.text = "Header Section #\(section) (manual load)" } } diff --git a/Example/ReusableDemo iOS/TableViewCells/MyHeaderTableView.xib b/Example/ReusableDemo iOS/TableViewCells/MyTableViewHeader.xib similarity index 91% rename from Example/ReusableDemo iOS/TableViewCells/MyHeaderTableView.xib rename to Example/ReusableDemo iOS/TableViewCells/MyTableViewHeader.xib index 173a14c..5cc2162 100755 --- a/Example/ReusableDemo iOS/TableViewCells/MyHeaderTableView.xib +++ b/Example/ReusableDemo iOS/TableViewCells/MyTableViewHeader.xib @@ -1,16 +1,16 @@ - + - + - + diff --git a/Example/ReusableDemo iOS/TableViewCells/MyXIBInfoCell.swift b/Example/ReusableDemo iOS/TableViewCells/MyXIBInfoCell.swift index 68187d2..ca815b2 100644 --- a/Example/ReusableDemo iOS/TableViewCells/MyXIBInfoCell.swift +++ b/Example/ReusableDemo iOS/TableViewCells/MyXIBInfoCell.swift @@ -20,7 +20,7 @@ import Reusable * Which in fact is just a convenience typealias that combines * `NibLoadable` & `Reusable` protocols. */ -final class MyXIBInfoCell: UITableViewCell, NibReusable { +final class MyXIBInfoCell: UITableViewCell, NibReusable, AutoRegistering { @IBOutlet private weak var titleLabel: UILabel! private var info: String = "" diff --git a/Example/ReusableDemo iOS/TableViewController.swift b/Example/ReusableDemo iOS/TableViewController.swift index 07b8e01..a32367c 100755 --- a/Example/ReusableDemo iOS/TableViewController.swift +++ b/Example/ReusableDemo iOS/TableViewController.swift @@ -16,29 +16,44 @@ final class TableViewController: UITableViewController { tableView.register(cellType: MySimpleColorCell.self) tableView.register(cellType: MyXIBTextCell.self) - tableView.register(cellType: MyXIBInfoCell.self) + + /* Since MyXIBInfoCell is marked as conforming to AutoRegistering, + there's no need to register this type ahead of time */ + // tableView.register(cellType: MyXIBInfoCell.self) /* No need to register this one, the UIStoryboard already auto-register its cells */ -// tableView.registerReusableCell(MyStoryBoardIndexPathCell) + // tableView.registerReusableCell(MyStoryBoardIndexPathCell) } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return MyHeaderTableView.height + switch section { + case 0: + return MyTableViewHeader.height + default: + return MyAutoRegisterTableViewHeader.height + } } override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let frame = CGRect( - x: 0, - y: 0, - width: tableView.bounds.size.width, - height: self.tableView(tableView, heightForHeaderInSection: section) - ) - // See the overridden `MyHeaderTableView.init(frame:)` initializer, which - // automatically loads the view content from its nib using loadNibContent() - let view = MyHeaderTableView(frame: frame) - - view.fillForSection(section) - return view + switch section { + case 0: + let frame = CGRect( + x: 0, + y: 0, + width: tableView.bounds.size.width, + height: self.tableView(tableView, heightForHeaderInSection: section) + ) + // See the overridden `MyHeaderTableView.init(frame:)` initializer, which + // automatically loads the view content from its nib using loadNibContent() + let view = MyTableViewHeader(frame: frame) + view.fillForSection(section) + return view + default: + // This header class is set to auto-register itself + let view: MyAutoRegisterTableViewHeader = tableView.dequeueReusableHeaderFooterView() + view.fillForSection(section) + return view + } } override func numberOfSections(in tableView: UITableView) -> Int { @@ -61,6 +76,7 @@ final class TableViewController: UITableViewController { textCell.fill("{section \(indexPath.section), row \(indexPath.row)}") return textCell case 2: + // Note that auto-register is enabled here let infoCell = tableView.dequeueReusableCell(for: indexPath) as MyXIBInfoCell infoCell.fill("InfoCell #\(indexPath.row)", info: "Info #\(indexPath.row)", details: "Details #\(indexPath.row)") return infoCell diff --git a/Example/ReusableDemo.xcodeproj/project.pbxproj b/Example/ReusableDemo.xcodeproj/project.pbxproj index 3128302..0e4cbc7 100644 --- a/Example/ReusableDemo.xcodeproj/project.pbxproj +++ b/Example/ReusableDemo.xcodeproj/project.pbxproj @@ -35,11 +35,13 @@ 37E3FC761E55CDD8000A7436 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37E3FC751E55CDD8000A7436 /* Assets.xcassets */; }; 37E3FC7E1E55D056000A7436 /* MyCustomWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E3FC7D1E55D056000A7436 /* MyCustomWidget.swift */; }; 37E3FC801E55D08C000A7436 /* MyCustomWidget.xib in Resources */ = {isa = PBXBuildFile; fileRef = 37E3FC7F1E55D08C000A7436 /* MyCustomWidget.xib */; }; - 3BC2191F1CFC259F003BE78C /* MyHeaderTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BC2191D1CFC259F003BE78C /* MyHeaderTableView.swift */; }; - 3BC219201CFC259F003BE78C /* MyHeaderTableView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3BC2191E1CFC259F003BE78C /* MyHeaderTableView.xib */; }; + 3BC2191F1CFC259F003BE78C /* MyTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BC2191D1CFC259F003BE78C /* MyTableViewHeader.swift */; }; + 3BC219201CFC259F003BE78C /* MyTableViewHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3BC2191E1CFC259F003BE78C /* MyTableViewHeader.xib */; }; 47EE563C1D66155100AD3E4D /* MyCustomWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EE563B1D66155100AD3E4D /* MyCustomWidget.swift */; }; 47EE563E1D66155D00AD3E4D /* MyCustomWidget.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47EE563D1D66155D00AD3E4D /* MyCustomWidget.xib */; }; 73E86102FC28DA0699B75437 /* Pods_ReusableDemo_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2606E6E047118D562E70F0CF /* Pods_ReusableDemo_tvOS.framework */; }; + B818B06E2119BCB100D0BF37 /* MyAutoRegisterTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B818B06C2119BCB100D0BF37 /* MyAutoRegisterTableViewHeader.swift */; }; + B818B06F2119BE8700D0BF37 /* MyAutoRegisterTableViewHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = B818B06D2119BCB100D0BF37 /* MyAutoRegisterTableViewHeader.xib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -78,12 +80,14 @@ 37E3FC771E55CDD8000A7436 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37E3FC7D1E55D056000A7436 /* MyCustomWidget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyCustomWidget.swift; sourceTree = ""; }; 37E3FC7F1E55D08C000A7436 /* MyCustomWidget.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyCustomWidget.xib; sourceTree = ""; }; - 3BC2191D1CFC259F003BE78C /* MyHeaderTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyHeaderTableView.swift; sourceTree = ""; }; - 3BC2191E1CFC259F003BE78C /* MyHeaderTableView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyHeaderTableView.xib; sourceTree = ""; }; + 3BC2191D1CFC259F003BE78C /* MyTableViewHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyTableViewHeader.swift; sourceTree = ""; }; + 3BC2191E1CFC259F003BE78C /* MyTableViewHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyTableViewHeader.xib; sourceTree = ""; }; 47EE563B1D66155100AD3E4D /* MyCustomWidget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyCustomWidget.swift; sourceTree = ""; }; 47EE563D1D66155D00AD3E4D /* MyCustomWidget.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyCustomWidget.xib; sourceTree = ""; }; 80A8538E60254C825B7D505B /* Pods-ReusableDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReusableDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ReusableDemo/Pods-ReusableDemo.debug.xcconfig"; sourceTree = ""; }; 868A47776F0B74DD17857FFE /* Pods_ReusableDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReusableDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B818B06C2119BCB100D0BF37 /* MyAutoRegisterTableViewHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAutoRegisterTableViewHeader.swift; sourceTree = ""; }; + B818B06D2119BCB100D0BF37 /* MyAutoRegisterTableViewHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MyAutoRegisterTableViewHeader.xib; sourceTree = ""; }; CFC3794861C2D883C20E9AC8 /* Pods-ReusableDemo iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReusableDemo iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS.debug.xcconfig"; sourceTree = ""; }; E7E0B2333D96C0FED6D45DD1 /* Pods-ReusableDemo tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReusableDemo tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS.debug.xcconfig"; sourceTree = ""; }; FB77CDB068583366F960D03D /* Pods-ReusableDemo iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReusableDemo iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS.release.xcconfig"; sourceTree = ""; }; @@ -171,8 +175,10 @@ 09B3461F1C4ED34F00BA041F /* TableView Cells */ = { isa = PBXGroup; children = ( - 3BC2191D1CFC259F003BE78C /* MyHeaderTableView.swift */, - 3BC2191E1CFC259F003BE78C /* MyHeaderTableView.xib */, + 3BC2191D1CFC259F003BE78C /* MyTableViewHeader.swift */, + 3BC2191E1CFC259F003BE78C /* MyTableViewHeader.xib */, + B818B06C2119BCB100D0BF37 /* MyAutoRegisterTableViewHeader.swift */, + B818B06D2119BCB100D0BF37 /* MyAutoRegisterTableViewHeader.xib */, 09B346201C4ED39700BA041F /* MyXIBTextCell.swift */, 09B346211C4ED39700BA041F /* MyXIBTextCell.xib */, 09B346261C4ED51600BA041F /* MyXIBInfoCell.swift */, @@ -347,9 +353,10 @@ 47EE563E1D66155D00AD3E4D /* MyCustomWidget.xib in Resources */, 09441AE21D32A0390029B8A6 /* InfoViewController.storyboard in Resources */, 09B346141C4ED26F00BA041F /* Assets.xcassets in Resources */, + B818B06F2119BE8700D0BF37 /* MyAutoRegisterTableViewHeader.xib in Resources */, 09B346251C4ED4CE00BA041F /* Default-568h@2x.png in Resources */, 09B346121C4ED26F00BA041F /* Main.storyboard in Resources */, - 3BC219201CFC259F003BE78C /* MyHeaderTableView.xib in Resources */, + 3BC219201CFC259F003BE78C /* MyTableViewHeader.xib in Resources */, 09B346421C4EF71900BA041F /* MyXIBIndexSquaceCell.xib in Resources */, 09B346291C4ED51600BA041F /* MyXIBInfoCell.xib in Resources */, ); @@ -496,13 +503,14 @@ 09B346411C4EF71900BA041F /* MyXIBIndexSquaceCell.swift in Sources */, 09B346341C4EDC7D00BA041F /* MyStoryBoardIndexPathCell.swift in Sources */, 09B346221C4ED39700BA041F /* MyXIBTextCell.swift in Sources */, + B818B06E2119BCB100D0BF37 /* MyAutoRegisterTableViewHeader.swift in Sources */, 47EE563C1D66155100AD3E4D /* MyCustomWidget.swift in Sources */, 09B3463C1C4EF46100BA041F /* MyStoryboardTextSquareCell.swift in Sources */, 09B3463E1C4EF4A400BA041F /* CollectionViewController.swift in Sources */, 09B3460F1C4ED26F00BA041F /* TableViewController.swift in Sources */, 09441AE41D32A0700029B8A6 /* InfoDetailViewController.swift in Sources */, 09B3460D1C4ED26F00BA041F /* AppDelegate.swift in Sources */, - 3BC2191F1CFC259F003BE78C /* MyHeaderTableView.swift in Sources */, + 3BC2191F1CFC259F003BE78C /* MyTableViewHeader.swift in Sources */, 09441AE61D32A07D0029B8A6 /* InfoViewController.swift in Sources */, 09B346281C4ED51600BA041F /* MyXIBInfoCell.swift in Sources */, 09B346441C4EF8B700BA041F /* CollectionHeaderView.swift in Sources */, diff --git a/README.md b/README.md index 166f6b5..ea372e7 100644 --- a/README.md +++ b/README.md @@ -131,11 +131,17 @@ final class NibBasedCollectionViewCell: UICollectionViewCell, NibReusable { ``` -## 2. Register your cells +## 2. Either enable AutoRegistering or manually register your cells +In order to have your cells automatically registered to a TableView/CollectionView when they are first used, simply add conformance to the `AutoRegistering` protocol. + +```swift +final class CustomCell: UITableViewCell, Reusable, AutoRegistering { } +``` + +If you've prototyped your cell in a Storyboard, there is no need to conform to 'AutoRegistering' or manually register, as this is done automatically by the Storyboard. -Unless you've prototyped your cell in a Storyboard, you'll have to register the cell class or Nib by code. -To do this, instead of calling `registerClass(…)` or `registerNib(…)` using a String-based `reuseIdentifier`, just call: +Alternatively you will have to register the cell class or Nib by code. To do this, just call: ```swift tableView.register(cellType: theCellClass.self) diff --git a/Sources/View/Reusable.swift b/Sources/View/Reusable.swift index 28f8e01..6de7f36 100644 --- a/Sources/View/Reusable.swift +++ b/Sources/View/Reusable.swift @@ -23,6 +23,13 @@ public protocol Reusable: class { /// to be able to dequeue them in a type-safe manner public typealias NibReusable = Reusable & NibLoadable +/// Make your `UITableViewCell`, `UITableViewHeaderFooterView`, and 'UICollectionViewCell' +/// subclasses conform to this protocol when you want to avoid having to call +/// register(cellType:) explicitly on your cell classes before being able +/// to dequeue them. Cell types conforming to this will auto-register the +/// cell if not registered already when you try to dequeue one for the first time. +public protocol AutoRegistering {} + // MARK: - Default implementation public extension Reusable { diff --git a/Sources/View/UICollectionView+Reusable.swift b/Sources/View/UICollectionView+Reusable.swift index 318ce38..a2efac2 100644 --- a/Sources/View/UICollectionView+Reusable.swift +++ b/Sources/View/UICollectionView+Reusable.swift @@ -11,6 +11,32 @@ import UIKit // MARK: Reusable support for UICollectionView public extension UICollectionView { + /** + Register a NIB-Based `UICollectionViewCell` subclass (conforming to `Reusable` & `NibLoadable`) + + - parameter cellType: the `UICollectionViewCell` (`Reusable` & `NibLoadable`-conforming) subclass to register + + - seealso: `register(_:,forCellWithReuseIdentifier:)` + */ + final func register(cellType: T.Type) + where T: NibReusable & AutoRegistering { + self.register(cellType.nib, forCellWithReuseIdentifier: cellType.reuseIdentifier) + setHasRegistered(cellType: cellType) + } + + /** + Register a NIB-Based `UICollectionViewCell` subclass (conforming to `Reusable` & `NibLoadable`) + + - parameter cellType: the `UICollectionViewCell` (`Reusable` & `NibLoadable`-conforming) subclass to register + + - seealso: `register(_:,forCellWithReuseIdentifier:)` + */ + final func register(cellType: T.Type) + where T: Reusable & AutoRegistering { + self.register(cellType.self, forCellWithReuseIdentifier: cellType.reuseIdentifier) + setHasRegistered(cellType: cellType) + } + /** Register a NIB-Based `UICollectionViewCell` subclass (conforming to `Reusable` & `NibLoadable`) @@ -19,7 +45,7 @@ public extension UICollectionView { - seealso: `register(_:,forCellWithReuseIdentifier:)` */ final func register(cellType: T.Type) - where T: Reusable & NibLoadable { + where T: NibReusable { self.register(cellType.nib, forCellWithReuseIdentifier: cellType.reuseIdentifier) } @@ -37,24 +63,70 @@ public extension UICollectionView { /** Returns a reusable `UICollectionViewCell` object for the class inferred by the return-type - + - parameter indexPath: The index path specifying the location of the cell. - parameter cellType: The cell class to dequeue + + - returns: A `Reusable`, `UICollectionViewCell` instance + + - note: The `cellType` parameter can generally be omitted and infered by the return type, + except when your type is in a variable and cannot be determined at compile time. + - seealso: `dequeueReusableCell(withReuseIdentifier:,for:)` + */ + final func dequeueReusableCell(for indexPath: IndexPath, cellType: T.Type = T.self) -> T + where T: Reusable & AutoRegistering { + if !hasRegistered(cellType: cellType) { + register(cellType: cellType) + } + return dequeueReusableCellInternal(for: indexPath) + } + /** + Returns a reusable `UICollectionViewCell` object for the class inferred by the return-type + + - parameter indexPath: The index path specifying the location of the cell. + - parameter cellType: The cell class to dequeue + - returns: A `Reusable`, `UICollectionViewCell` instance + + - note: The `cellType` parameter can generally be omitted and infered by the return type, + except when your type is in a variable and cannot be determined at compile time. + - seealso: `dequeueReusableCell(withReuseIdentifier:,for:)` + */ + final func dequeueReusableCell(for indexPath: IndexPath, cellType: T.Type = T.self) -> T + where T: NibReusable & AutoRegistering { + if !hasRegistered(cellType: cellType) { + register(cellType: cellType) + } + return dequeueReusableCellInternal(for: indexPath) + } + /** + Returns a reusable `UICollectionViewCell` object for the class inferred by the return-type + + - parameter indexPath: The index path specifying the location of the cell. + - parameter cellType: The cell class to dequeue + + - returns: A `Reusable`, `UICollectionViewCell` instance + - note: The `cellType` parameter can generally be omitted and infered by the return type, except when your type is in a variable and cannot be determined at compile time. - seealso: `dequeueReusableCell(withReuseIdentifier:,for:)` */ final func dequeueReusableCell(for indexPath: IndexPath, cellType: T.Type = T.self) -> T + where T: Reusable { + return dequeueReusableCellInternal(for: indexPath) + } + + final private func dequeueReusableCellInternal(for indexPath: IndexPath, + cellType: T.Type = T.self) -> T where T: Reusable { let bareCell = self.dequeueReusableCell(withReuseIdentifier: cellType.reuseIdentifier, for: indexPath) guard let cell = bareCell as? T else { fatalError( "Failed to dequeue a cell with identifier \(cellType.reuseIdentifier) matching type \(cellType.self). " + "Check that the reuseIdentifier is set properly in your XIB/Storyboard " - + "and that you registered the cell beforehand" + + "and that you registered the cell beforehand or conformed to AutoRegistering" ) } return cell @@ -63,11 +135,51 @@ public extension UICollectionView { /** Register a NIB-Based `UICollectionReusableView` subclass (conforming to `Reusable` & `NibLoadable`) as a Supplementary View + + - parameter supplementaryViewType: the `UIView` (`Reusable` & `NibLoadable`-conforming) subclass + to register as Supplementary View + - parameter elementKind: The kind of supplementary view to create. + + - seealso: `register(_:,forSupplementaryViewOfKind:,withReuseIdentifier:)` + */ + final func register(supplementaryViewType: T.Type, ofKind elementKind: String) + where T: NibReusable & AutoRegistering { + self.register( + supplementaryViewType.nib, + forSupplementaryViewOfKind: elementKind, + withReuseIdentifier: supplementaryViewType.reuseIdentifier + ) + setHasRegistered(supplementaryViewType: supplementaryViewType, ofKind: elementKind) + } + /** + Register a NIB-Based `UICollectionReusableView` subclass (conforming to `Reusable` & `NibLoadable`) + as a Supplementary View + - parameter supplementaryViewType: the `UIView` (`Reusable` & `NibLoadable`-conforming) subclass to register as Supplementary View - parameter elementKind: The kind of supplementary view to create. + + - seealso: `register(_:,forSupplementaryViewOfKind:,withReuseIdentifier:)` + */ + final func register(supplementaryViewType: T.Type, ofKind elementKind: String) + where T: Reusable & AutoRegistering { + self.register( + supplementaryViewType.self, + forSupplementaryViewOfKind: elementKind, + withReuseIdentifier: supplementaryViewType.reuseIdentifier + ) + setHasRegistered(supplementaryViewType: supplementaryViewType, ofKind: elementKind) + } + /** + Register a NIB-Based `UICollectionReusableView` subclass (conforming to `Reusable` & `NibLoadable`) + as a Supplementary View + + - parameter supplementaryViewType: the `UIView` (`Reusable` & `NibLoadable`-conforming) subclass + to register as Supplementary View + - parameter elementKind: The kind of supplementary view to create. + - seealso: `register(_:,forSupplementaryViewOfKind:,withReuseIdentifier:)` */ final func register(supplementaryViewType: T.Type, ofKind elementKind: String) @@ -96,6 +208,50 @@ public extension UICollectionView { ) } + /** + Returns a reusable `UICollectionReusableView` object for the class inferred by the return-type + + - parameter elementKind: The kind of supplementary view to retrieve. + - parameter indexPath: The index path specifying the location of the cell. + - parameter viewType: The view class to dequeue + + - returns: A `Reusable`, `UICollectionReusableView` instance + + - note: The `viewType` parameter can generally be omitted and infered by the return type, + except when your type is in a variable and cannot be determined at compile time. + - seealso: `dequeueReusableSupplementaryView(ofKind:,withReuseIdentifier:,for:)` + */ + final func dequeueReusableSupplementaryView + (ofKind elementKind: String, for indexPath: IndexPath, viewType: T.Type = T.self) -> T + where T: Reusable & AutoRegistering { + if !hasRegistered(supplementaryViewType: viewType, ofKind: elementKind) { + register(supplementaryViewType: viewType, ofKind: elementKind) + } + return dequeueReusableSupplementaryViewInternal(ofKind: elementKind, for: indexPath) + } + + /** + Returns a reusable `UICollectionReusableView` object for the class inferred by the return-type + + - parameter elementKind: The kind of supplementary view to retrieve. + - parameter indexPath: The index path specifying the location of the cell. + - parameter viewType: The view class to dequeue + + - returns: A `Reusable`, `UICollectionReusableView` instance + + - note: The `viewType` parameter can generally be omitted and infered by the return type, + except when your type is in a variable and cannot be determined at compile time. + - seealso: `dequeueReusableSupplementaryView(ofKind:,withReuseIdentifier:,for:)` + */ + final func dequeueReusableSupplementaryView + (ofKind elementKind: String, for indexPath: IndexPath, viewType: T.Type = T.self) -> T + where T: NibReusable & AutoRegistering { + if !hasRegistered(supplementaryViewType: viewType, ofKind: elementKind) { + register(supplementaryViewType: viewType, ofKind: elementKind) + } + return dequeueReusableSupplementaryViewInternal(ofKind: elementKind, for: indexPath) + } + /** Returns a reusable `UICollectionReusableView` object for the class inferred by the return-type @@ -110,6 +266,12 @@ public extension UICollectionView { - seealso: `dequeueReusableSupplementaryView(ofKind:,withReuseIdentifier:,for:)` */ final func dequeueReusableSupplementaryView + (ofKind elementKind: String, for indexPath: IndexPath, viewType: T.Type = T.self) -> T + where T: Reusable { + return dequeueReusableSupplementaryViewInternal(ofKind: elementKind, for: indexPath) + } + + final private func dequeueReusableSupplementaryViewInternal (ofKind elementKind: String, for indexPath: IndexPath, viewType: T.Type = T.self) -> T where T: Reusable { let view = self.dequeueReusableSupplementaryView( @@ -122,9 +284,46 @@ public extension UICollectionView { "Failed to dequeue a supplementary view with identifier \(viewType.reuseIdentifier) " + "matching type \(viewType.self). " + "Check that the reuseIdentifier is set properly in your XIB/Storyboard " - + "and that you registered the supplementary view beforehand" + + "and that you registered the supplementary view beforehand or conformed to AutoRegistering" ) } return typedView } } + +private var registeredCellTypesKey: Void? + +private extension UICollectionView { + private class RegisteredCellTypes { + var cellReuseIdentifiers: Set = [] + var supplementaryViewReuseIdentifiers: [String: String] = [:] //[ElementKind: ReuseIdentifier] + } + + private var registeredCellTypes: RegisteredCellTypes { + if let obj = (objc_getAssociatedObject(self, ®isteredCellTypesKey) as? RegisteredCellTypes) { + return obj + } else { + let obj = RegisteredCellTypes() + objc_setAssociatedObject(self, ®isteredCellTypesKey, obj, .OBJC_ASSOCIATION_RETAIN) //Create assoc. object + return obj + } + } + + final private func hasRegistered(cellType type: T.Type) -> Bool where T: Reusable { + return registeredCellTypes.cellReuseIdentifiers.contains(type.reuseIdentifier) + } + + final private func setHasRegistered(cellType type: T.Type) where T: Reusable { + registeredCellTypes.cellReuseIdentifiers.insert(type.reuseIdentifier) + } + + final private func hasRegistered(supplementaryViewType type: T.Type, + ofKind elementKind: String) -> Bool where T: Reusable { + return (registeredCellTypes.supplementaryViewReuseIdentifiers[elementKind] == type.reuseIdentifier) + } + + final private func setHasRegistered(supplementaryViewType type: T.Type, + ofKind elementKind: String) where T: Reusable { + registeredCellTypes.supplementaryViewReuseIdentifiers[elementKind] = type.reuseIdentifier + } +} diff --git a/Sources/View/UITableView+Reusable.swift b/Sources/View/UITableView+Reusable.swift index fc36044..17c85bc 100644 --- a/Sources/View/UITableView+Reusable.swift +++ b/Sources/View/UITableView+Reusable.swift @@ -19,7 +19,7 @@ public extension UITableView { - seealso: `register(_:,forCellReuseIdentifier:)` */ final func register(cellType: T.Type) - where T: Reusable & NibLoadable { + where T: NibReusable { self.register(cellType.nib, forCellReuseIdentifier: cellType.reuseIdentifier) } @@ -47,13 +47,107 @@ public extension UITableView { except when your type is in a variable and cannot be determined at compile time. - seealso: `dequeueReusableCell(withIdentifier:,for:)` */ - final func dequeueReusableCell(for indexPath: IndexPath, cellType: T.Type = T.self) -> T + final func dequeueReusableCell( + for indexPath: IndexPath, + cellType: T.Type = T.self) -> T + where T: Reusable & AutoRegistering { + return dequeueReusableCell( + for: indexPath, + cellType: cellType, + // use the `register(cellType:)` implementation from Reusable conformance + registerClosure: { self.register(cellType: cellType) } + ) + } + + /** + Returns a reusable `UITableViewCell` object for the class inferred by the return-type + + - parameter indexPath: The index path specifying the location of the cell. + - parameter cellType: The cell class to dequeue + + - returns: A `Reusable`, `UITableViewCell` instance + + - note: The `cellType` parameter can generally be omitted and infered by the return type, + except when your type is in a variable and cannot be determined at compile time. + - seealso: `dequeueReusableCell(withIdentifier:,for:)` + */ + final func dequeueReusableCell( + for indexPath: IndexPath, + cellType: T.Type = T.self) -> T + where T: NibReusable & AutoRegistering { + return dequeueReusableCell( + for: indexPath, + cellType: cellType, + // use the `register(cellType:)` implementation from NibReusable conformance + registerClosure: { self.register(cellType: cellType) } + ) + } + + /** + Returns a reusable `UITableViewCell` object for the class inferred by the return-type + + - parameter indexPath: The index path specifying the location of the cell. + - parameter cellType: The cell class to dequeue + + - returns: A `Reusable`, `UITableViewCell` instance + + - note: The `cellType` parameter can generally be omitted and infered by the return type, + except when your type is in a variable and cannot be determined at compile time. + - seealso: `dequeueReusableCell(withIdentifier:,for:)` + */ + final func dequeueReusableCell( + for indexPath: IndexPath, + cellType: T.Type = T.self) -> T where T: Reusable { - guard let cell = self.dequeueReusableCell(withIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else { + return dequeueReusableCell( + for: indexPath, + cellType: cellType, + registerClosure: nil + ) + } + + /** + Returns a reusable `UITableViewCell` object for the class inferred by the return-type + + - parameter indexPath: The index path specifying the location of the cell. + - parameter cellType: The cell class to dequeue + + - returns: A `Reusable`, `UITableViewCell` instance + + - note: The `cellType` parameter can generally be omitted and infered by the return type, + except when your type is in a variable and cannot be determined at compile time. + - seealso: `dequeueReusableCell(withIdentifier:,for:)` + */ + final func dequeueReusableCell( + for indexPath: IndexPath, + cellType: T.Type = T.self) -> T + where T: NibReusable { + return dequeueReusableCell( + for: indexPath, + cellType: cellType, + registerClosure: nil + ) + } + + private func dequeueReusableCell( + for indexPath: IndexPath, + cellType: T.Type = T.self, + registerClosure: (() -> Void)?) -> T + where T: Reusable { + if let registerClosure = registerClosure { + if let bareCell = self.dequeueReusableCell(withIdentifier: cellType.reuseIdentifier) as? T { + return bareCell // Get a cell if we can + } else { + registerClosure() // Register class or nib + } + } + let bareCell = self.dequeueReusableCell(withIdentifier: cellType.reuseIdentifier, for: indexPath) as? T + guard let cell = bareCell else { fatalError( - "Failed to dequeue a cell with identifier \(cellType.reuseIdentifier) matching type \(cellType.self). " + "Failed to dequeue a cell with identifier \(cellType.reuseIdentifier)" + + "matching type \(cellType.self). " + "Check that the reuseIdentifier is set properly in your XIB/Storyboard " - + "and that you registered the cell beforehand" + + "and that you registered the cell beforehand or conformed to AutoRegistering" ) } return cell @@ -68,7 +162,7 @@ public extension UITableView { - seealso: `register(_:,forHeaderFooterViewReuseIdentifier:)` */ final func register(headerFooterViewType: T.Type) - where T: Reusable & NibLoadable { + where T: NibReusable { self.register(headerFooterViewType.nib, forHeaderFooterViewReuseIdentifier: headerFooterViewType.reuseIdentifier) } @@ -95,14 +189,47 @@ public extension UITableView { except when your type is in a variable and cannot be determined at compile time. - seealso: `dequeueReusableHeaderFooterView(withIdentifier:)` */ - final func dequeueReusableHeaderFooterView(_ viewType: T.Type = T.self) -> T? + final func dequeueReusableHeaderFooterView(_ viewType: T.Type = T.self) -> T + where T: Reusable & AutoRegistering { + return dequeueReusableHeaderFooterView( + registerClosure: { self.register(headerFooterViewType: viewType) } + ) + } + + /** + Returns a reusable `UITableViewHeaderFooterView` object for the class inferred by the return-type + + - parameter viewType: The view class to dequeue + + - returns: A `Reusable`, `UITableViewHeaderFooterView` instance + + - note: The `viewType` parameter can generally be omitted and infered by the return type, + except when your type is in a variable and cannot be determined at compile time. + - seealso: `dequeueReusableHeaderFooterView(withIdentifier:)` + */ + final func dequeueReusableHeaderFooterView(_ viewType: T.Type = T.self) -> T + where T: NibReusable & AutoRegistering { + return dequeueReusableHeaderFooterView( + registerClosure: { self.register(headerFooterViewType: viewType) } + ) + } + + final func dequeueReusableHeaderFooterView(_ viewType: T.Type = T.self, + registerClosure: (() -> Void)?) -> T where T: Reusable { - guard let view = self.dequeueReusableHeaderFooterView(withIdentifier: viewType.reuseIdentifier) as? T? else { + if let registerClosure = registerClosure { + if let view = self.dequeueReusableHeaderFooterView(withIdentifier: viewType.reuseIdentifier) as? T { + return view // Get a cell if we can + } else { + registerClosure() // Register class or nib + } + } + guard let view = self.dequeueReusableHeaderFooterView(withIdentifier: viewType.reuseIdentifier) as? T else { fatalError( "Failed to dequeue a header/footer with identifier \(viewType.reuseIdentifier) " + "matching type \(viewType.self). " + "Check that the reuseIdentifier is set properly in your XIB/Storyboard " - + "and that you registered the header/footer beforehand" + + "and that you registered the header/footer beforehand or conformed to AutoRegistering" ) } return view From 4208d1695bd0a7e762272fe17a92a5732d3a7c5f Mon Sep 17 00:00:00 2001 From: apptekstudios Date: Mon, 15 Oct 2018 00:22:58 +1000 Subject: [PATCH 2/5] Minor Changes --- ...=> MyTableViewHeaderAutoRegistering.swift} | 2 +- ...b => MyTableViewHeaderAutoRegistering.xib} | 7 +++--- .../TableViewController.swift | 4 ++-- .../ReusableDemo.xcodeproj/project.pbxproj | 24 ++++++++++++------- README.md | 1 + Sources/View/UICollectionView+Reusable.swift | 2 +- Sources/View/UITableView+Reusable.swift | 1 + 7 files changed, 25 insertions(+), 16 deletions(-) rename Example/ReusableDemo iOS/TableViewCells/{MyAutoRegisterTableViewHeader.swift => MyTableViewHeaderAutoRegistering.swift} (88%) rename Example/ReusableDemo iOS/TableViewCells/{MyAutoRegisterTableViewHeader.xib => MyTableViewHeaderAutoRegistering.xib} (92%) diff --git a/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.swift b/Example/ReusableDemo iOS/TableViewCells/MyTableViewHeaderAutoRegistering.swift similarity index 88% rename from Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.swift rename to Example/ReusableDemo iOS/TableViewCells/MyTableViewHeaderAutoRegistering.swift index 9854d7e..e3117c5 100755 --- a/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.swift +++ b/Example/ReusableDemo iOS/TableViewCells/MyTableViewHeaderAutoRegistering.swift @@ -20,7 +20,7 @@ import Reusable * Which in fact is just a convenience typealias that combines * `NibLoadable` & `Reusable` protocols. */ -final class MyAutoRegisterTableViewHeader: UITableViewHeaderFooterView, NibReusable, AutoRegistering { +final class MyTableViewHeaderAutoRegistering: UITableViewHeaderFooterView, NibReusable, AutoRegistering { @IBOutlet private weak var titleLabel: UILabel! diff --git a/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.xib b/Example/ReusableDemo iOS/TableViewCells/MyTableViewHeaderAutoRegistering.xib similarity index 92% rename from Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.xib rename to Example/ReusableDemo iOS/TableViewCells/MyTableViewHeaderAutoRegistering.xib index 3f243f7..2c25551 100755 --- a/Example/ReusableDemo iOS/TableViewCells/MyAutoRegisterTableViewHeader.xib +++ b/Example/ReusableDemo iOS/TableViewCells/MyTableViewHeaderAutoRegistering.xib @@ -1,18 +1,17 @@ - + - - + - + diff --git a/Example/ReusableDemo iOS/TableViewController.swift b/Example/ReusableDemo iOS/TableViewController.swift index a32367c..00ae349 100755 --- a/Example/ReusableDemo iOS/TableViewController.swift +++ b/Example/ReusableDemo iOS/TableViewController.swift @@ -30,7 +30,7 @@ final class TableViewController: UITableViewController { case 0: return MyTableViewHeader.height default: - return MyAutoRegisterTableViewHeader.height + return MyTableViewHeaderAutoRegistering.height } } @@ -50,7 +50,7 @@ final class TableViewController: UITableViewController { return view default: // This header class is set to auto-register itself - let view: MyAutoRegisterTableViewHeader = tableView.dequeueReusableHeaderFooterView() + let view: MyTableViewHeaderAutoRegistering = tableView.dequeueReusableHeaderFooterView() view.fillForSection(section) return view } diff --git a/Example/ReusableDemo.xcodeproj/project.pbxproj b/Example/ReusableDemo.xcodeproj/project.pbxproj index ca93b35..60a666e 100644 --- a/Example/ReusableDemo.xcodeproj/project.pbxproj +++ b/Example/ReusableDemo.xcodeproj/project.pbxproj @@ -34,11 +34,13 @@ 37E3FC761E55CDD8000A7436 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37E3FC751E55CDD8000A7436 /* Assets.xcassets */; }; 37E3FC7E1E55D056000A7436 /* MyCustomWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E3FC7D1E55D056000A7436 /* MyCustomWidget.swift */; }; 37E3FC801E55D08C000A7436 /* MyCustomWidget.xib in Resources */ = {isa = PBXBuildFile; fileRef = 37E3FC7F1E55D08C000A7436 /* MyCustomWidget.xib */; }; - 3BC2191F1CFC259F003BE78C /* MyHeaderTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BC2191D1CFC259F003BE78C /* MyHeaderTableView.swift */; }; - 3BC219201CFC259F003BE78C /* MyHeaderTableView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3BC2191E1CFC259F003BE78C /* MyHeaderTableView.xib */; }; 47EE563C1D66155100AD3E4D /* MyCustomWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EE563B1D66155100AD3E4D /* MyCustomWidget.swift */; }; 47EE563E1D66155D00AD3E4D /* MyCustomWidget.xib in Resources */ = {isa = PBXBuildFile; fileRef = 47EE563D1D66155D00AD3E4D /* MyCustomWidget.xib */; }; 9FA94C08BEF301B3E3BDC872 /* Pods_ReusableDemo_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F2D22CAD76679D19CD171C1 /* Pods_ReusableDemo_tvOS.framework */; }; + B8CF34C82173864C0066D6BF /* MyTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CF34C62173864C0066D6BF /* MyTableViewHeader.swift */; }; + B8CF34C92173864C0066D6BF /* MyTableViewHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = B8CF34C72173864C0066D6BF /* MyTableViewHeader.xib */; }; + B8CF34CC217386680066D6BF /* MyTableViewHeaderAutoRegistering.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8CF34CA217386680066D6BF /* MyTableViewHeaderAutoRegistering.swift */; }; + B8CF34CD217386680066D6BF /* MyTableViewHeaderAutoRegistering.xib in Resources */ = {isa = PBXBuildFile; fileRef = B8CF34CB217386680066D6BF /* MyTableViewHeaderAutoRegistering.xib */; }; E5B86DD32EF6226743A8E042 /* Pods_ReusableDemo_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF21AA4AB6E6CEF7985FF09B /* Pods_ReusableDemo_iOS.framework */; }; /* End PBXBuildFile section */ @@ -75,13 +77,15 @@ 37E3FC771E55CDD8000A7436 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37E3FC7D1E55D056000A7436 /* MyCustomWidget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyCustomWidget.swift; sourceTree = ""; }; 37E3FC7F1E55D08C000A7436 /* MyCustomWidget.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyCustomWidget.xib; sourceTree = ""; }; - 3BC2191D1CFC259F003BE78C /* MyHeaderTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyHeaderTableView.swift; sourceTree = ""; }; - 3BC2191E1CFC259F003BE78C /* MyHeaderTableView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyHeaderTableView.xib; sourceTree = ""; }; 4033B8B5AA57F6CB717FCF24 /* Pods-ReusableDemo iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReusableDemo iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-ReusableDemo iOS/Pods-ReusableDemo iOS.release.xcconfig"; sourceTree = ""; }; 47EE563B1D66155100AD3E4D /* MyCustomWidget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyCustomWidget.swift; sourceTree = ""; }; 47EE563D1D66155D00AD3E4D /* MyCustomWidget.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyCustomWidget.xib; sourceTree = ""; }; 4F2D22CAD76679D19CD171C1 /* Pods_ReusableDemo_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReusableDemo_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4F85C1AE1D6502CAE2A6E6AC /* Pods-ReusableDemo tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReusableDemo tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS.debug.xcconfig"; sourceTree = ""; }; + B8CF34C62173864C0066D6BF /* MyTableViewHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyTableViewHeader.swift; sourceTree = ""; }; + B8CF34C72173864C0066D6BF /* MyTableViewHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyTableViewHeader.xib; sourceTree = ""; }; + B8CF34CA217386680066D6BF /* MyTableViewHeaderAutoRegistering.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyTableViewHeaderAutoRegistering.swift; sourceTree = ""; }; + B8CF34CB217386680066D6BF /* MyTableViewHeaderAutoRegistering.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyTableViewHeaderAutoRegistering.xib; sourceTree = ""; }; D8F45C0C4C06E7B1B16AC822 /* Pods-ReusableDemo tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReusableDemo tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-ReusableDemo tvOS/Pods-ReusableDemo tvOS.release.xcconfig"; sourceTree = ""; }; FF21AA4AB6E6CEF7985FF09B /* Pods_ReusableDemo_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReusableDemo_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -168,8 +172,10 @@ 09B3461F1C4ED34F00BA041F /* TableView Cells */ = { isa = PBXGroup; children = ( - 3BC2191D1CFC259F003BE78C /* MyHeaderTableView.swift */, - 3BC2191E1CFC259F003BE78C /* MyHeaderTableView.xib */, + B8CF34C62173864C0066D6BF /* MyTableViewHeader.swift */, + B8CF34C72173864C0066D6BF /* MyTableViewHeader.xib */, + B8CF34CA217386680066D6BF /* MyTableViewHeaderAutoRegistering.swift */, + B8CF34CB217386680066D6BF /* MyTableViewHeaderAutoRegistering.xib */, 09B346201C4ED39700BA041F /* MyXIBTextCell.swift */, 09B346211C4ED39700BA041F /* MyXIBTextCell.xib */, 09B346261C4ED51600BA041F /* MyXIBInfoCell.swift */, @@ -335,13 +341,14 @@ files = ( 09B346231C4ED39700BA041F /* MyXIBTextCell.xib in Resources */, 09B346461C4EF8F600BA041F /* CollectionHeaderView.xib in Resources */, + B8CF34CD217386680066D6BF /* MyTableViewHeaderAutoRegistering.xib in Resources */, 09B346171C4ED26F00BA041F /* LaunchScreen.storyboard in Resources */, 47EE563E1D66155D00AD3E4D /* MyCustomWidget.xib in Resources */, 09441AE21D32A0390029B8A6 /* InfoViewController.storyboard in Resources */, 09B346141C4ED26F00BA041F /* Assets.xcassets in Resources */, 09B346251C4ED4CE00BA041F /* Default-568h@2x.png in Resources */, 09B346121C4ED26F00BA041F /* Main.storyboard in Resources */, - 3BC219201CFC259F003BE78C /* MyHeaderTableView.xib in Resources */, + B8CF34C92173864C0066D6BF /* MyTableViewHeader.xib in Resources */, 09B346421C4EF71900BA041F /* MyXIBIndexSquaceCell.xib in Resources */, 09B346291C4ED51600BA041F /* MyXIBInfoCell.xib in Resources */, ); @@ -474,16 +481,17 @@ 09B346411C4EF71900BA041F /* MyXIBIndexSquaceCell.swift in Sources */, 09B346341C4EDC7D00BA041F /* MyStoryBoardIndexPathCell.swift in Sources */, 09B346221C4ED39700BA041F /* MyXIBTextCell.swift in Sources */, + B8CF34C82173864C0066D6BF /* MyTableViewHeader.swift in Sources */, 47EE563C1D66155100AD3E4D /* MyCustomWidget.swift in Sources */, 09B3463C1C4EF46100BA041F /* MyStoryboardTextSquareCell.swift in Sources */, 09B3463E1C4EF4A400BA041F /* CollectionViewController.swift in Sources */, 09B3460F1C4ED26F00BA041F /* TableViewController.swift in Sources */, 09441AE41D32A0700029B8A6 /* InfoDetailViewController.swift in Sources */, 09B3460D1C4ED26F00BA041F /* AppDelegate.swift in Sources */, - 3BC2191F1CFC259F003BE78C /* MyHeaderTableView.swift in Sources */, 09441AE61D32A07D0029B8A6 /* InfoViewController.swift in Sources */, 09B346281C4ED51600BA041F /* MyXIBInfoCell.swift in Sources */, 09B346441C4EF8B700BA041F /* CollectionHeaderView.swift in Sources */, + B8CF34CC217386680066D6BF /* MyTableViewHeaderAutoRegistering.swift in Sources */, 09B3462B1C4ED6C400BA041F /* MySimpleColorCell.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/README.md b/README.md index ea372e7..069a651 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ final class NibBasedCollectionViewCell: UICollectionViewCell, NibReusable { ## 2. Either enable AutoRegistering or manually register your cells + In order to have your cells automatically registered to a TableView/CollectionView when they are first used, simply add conformance to the `AutoRegistering` protocol. ```swift diff --git a/Sources/View/UICollectionView+Reusable.swift b/Sources/View/UICollectionView+Reusable.swift index a2efac2..b30de8a 100644 --- a/Sources/View/UICollectionView+Reusable.swift +++ b/Sources/View/UICollectionView+Reusable.swift @@ -319,7 +319,7 @@ private extension UICollectionView { final private func hasRegistered(supplementaryViewType type: T.Type, ofKind elementKind: String) -> Bool where T: Reusable { - return (registeredCellTypes.supplementaryViewReuseIdentifiers[elementKind] == type.reuseIdentifier) + return registeredCellTypes.supplementaryViewReuseIdentifiers[elementKind] == type.reuseIdentifier } final private func setHasRegistered(supplementaryViewType type: T.Type, diff --git a/Sources/View/UITableView+Reusable.swift b/Sources/View/UITableView+Reusable.swift index 17c85bc..1250e37 100644 --- a/Sources/View/UITableView+Reusable.swift +++ b/Sources/View/UITableView+Reusable.swift @@ -214,6 +214,7 @@ public extension UITableView { ) } + private final func dequeueReusableHeaderFooterView(_ viewType: T.Type = T.self, registerClosure: (() -> Void)?) -> T where T: Reusable { From f27c2e968fd0d70da031c3adaa20a576c20d32af Mon Sep 17 00:00:00 2001 From: apptekstudios Date: Mon, 15 Oct 2018 00:32:51 +1000 Subject: [PATCH 3/5] Update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15caec6..a3c0d04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ ## Master -_No new commits since latest release yet_ +* Add support for automatic cell registration by conforming to 'AutoRegistering' (table view / collection view). +[@apptekstudios](https://github.com/apptekstudios) +[#63](https://github.com/AliSoftware/Reusable/pull/63) ## 4.0.4 From 0eb0c28353e754360a3ee4dd7c5a02de736e8b72 Mon Sep 17 00:00:00 2001 From: apptekstudios Date: Sat, 6 Apr 2019 12:02:15 +1000 Subject: [PATCH 4/5] Add support to retrieve the topmost view when loading nib content (NibOwnerLoadable) --- Sources/View/NibOwnerLoadable.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/View/NibOwnerLoadable.swift b/Sources/View/NibOwnerLoadable.swift index 3cd1711..fa8480b 100644 --- a/Sources/View/NibOwnerLoadable.swift +++ b/Sources/View/NibOwnerLoadable.swift @@ -36,9 +36,12 @@ public extension NibOwnerLoadable where Self: UIView { /** Adds content loaded from the nib to the end of the receiver's list of subviews and adds constraints automatically. */ - func loadNibContent() { + @discardableResult + func loadNibContent() -> UIView? { let layoutAttributes: [NSLayoutConstraint.Attribute] = [.top, .leading, .bottom, .trailing] + var firstView: UIView? for case let view as UIView in Self.nib.instantiate(withOwner: self, options: nil) { + if firstView == nil { firstView = view } view.translatesAutoresizingMaskIntoConstraints = false self.addSubview(view) NSLayoutConstraint.activate(layoutAttributes.map { attribute in @@ -50,6 +53,7 @@ public extension NibOwnerLoadable where Self: UIView { ) }) } + return firstView } } From 52b34d6b35d5d222bf96060c777ad24febd18b72 Mon Sep 17 00:00:00 2001 From: apptekstudios Date: Sat, 4 May 2019 11:44:45 +1000 Subject: [PATCH 5/5] Bump swift version to 5.0 --- Example/Pods/Pods.xcodeproj/project.pbxproj | 29 +++++++++++-------- .../xcschemes/Reusable-iOS.xcscheme | 2 +- .../xcschemes/Reusable-tvOS.xcscheme | 2 +- .../ReusableDemo.xcodeproj/project.pbxproj | 6 ++-- .../xcschemes/ReusableDemo iOS.xcscheme | 2 +- .../xcschemes/ReusableDemo tvOS.xcscheme | 2 +- Reusable.podspec | 2 +- 7 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index f0b4dc4..e3687d7 100644 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -56,10 +56,10 @@ /* Begin PBXFileReference section */ 029963D2DD2C3E43DF26B9E6CFC4C77C /* Reusable-tvOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "Reusable-tvOS-prefix.pch"; path = "../Reusable-tvOS/Reusable-tvOS-prefix.pch"; sourceTree = ""; }; - 032F07628656348BA344539DF2F3FDB2 /* Reusable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Reusable.framework; path = "Reusable-tvOS.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 032F07628656348BA344539DF2F3FDB2 /* Reusable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Reusable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0447347B9A1D4FB9213447A363F7039C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 0FBD092B0B485DA6C7B90BE206901D63 /* Pods-ReusableDemo tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReusableDemo tvOS.release.xcconfig"; sourceTree = ""; }; - 134568E37290F577BF1196CE3781E88A /* Reusable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Reusable.framework; path = "Reusable-iOS.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 134568E37290F577BF1196CE3781E88A /* Reusable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Reusable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1E9CB32CE05A90E5172D6D051DD06C14 /* Pods-ReusableDemo tvOS-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-ReusableDemo tvOS-acknowledgements.markdown"; sourceTree = ""; }; 1ED6979FA83E22940E9242F74ECAFF2A /* Reusable-iOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Reusable-iOS-dummy.m"; sourceTree = ""; }; 2252BDFE7D9DF619FDD525C082B88752 /* NibOwnerLoadable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NibOwnerLoadable.swift; path = Sources/View/NibOwnerLoadable.swift; sourceTree = ""; }; @@ -75,15 +75,15 @@ 5892AC97FA3ED1A5B9672D91235E50A0 /* Reusable-tvOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "Reusable-tvOS-umbrella.h"; path = "../Reusable-tvOS/Reusable-tvOS-umbrella.h"; sourceTree = ""; }; 59FF06E4BEF0F7688B1F724EB17FA572 /* StoryboardBased.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StoryboardBased.swift; path = Sources/Storyboard/StoryboardBased.swift; sourceTree = ""; }; 5AFEACE7A71F4931B930EB6D84C5C91F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - 5B5B35512DA1A50AAFAE6CF87A634BF6 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE; sourceTree = ""; }; - 60C791B4753934D6F226F344C203602E /* Pods_ReusableDemo_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_ReusableDemo_iOS.framework; path = "Pods-ReusableDemo iOS.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5B5B35512DA1A50AAFAE6CF87A634BF6 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + 60C791B4753934D6F226F344C203602E /* Pods_ReusableDemo_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReusableDemo_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 62D264D4244F785EB7C4672C8F079E34 /* Reusable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reusable.swift; path = Sources/View/Reusable.swift; sourceTree = ""; }; 651C55EADF4A57B9F079395A27F61ABC /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6C4EA458C8961A4156B23CF70C2F5D1A /* Pods-ReusableDemo tvOS-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ReusableDemo tvOS-frameworks.sh"; sourceTree = ""; }; 75BE09819782C98834791EFD9D29FF3B /* Pods-ReusableDemo iOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-ReusableDemo iOS-dummy.m"; sourceTree = ""; }; 8409AF22BF14FCADAFB835B8DA7539F9 /* UICollectionView+Reusable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UICollectionView+Reusable.swift"; path = "Sources/View/UICollectionView+Reusable.swift"; sourceTree = ""; }; - 8CF050962AB868C4567DD94B5A8051C1 /* Reusable.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; path = Reusable.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 8CF050962AB868C4567DD94B5A8051C1 /* Reusable.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; path = Reusable.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 961CF8EA017975C422786939C10D48DB /* Reusable-tvOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; name = "Reusable-tvOS.modulemap"; path = "../Reusable-tvOS/Reusable-tvOS.modulemap"; sourceTree = ""; }; 997B29124B8AD227F6B17CE7D11B0953 /* Reusable-iOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Reusable-iOS.modulemap"; sourceTree = ""; }; 9E51095A3435FC405B95D01CEB2E6761 /* Reusable-iOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Reusable-iOS-umbrella.h"; sourceTree = ""; }; @@ -97,11 +97,11 @@ B8F436E7630A5B236CBEF9145E88B2E2 /* Pods-ReusableDemo iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReusableDemo iOS.debug.xcconfig"; sourceTree = ""; }; C40FFB95E0E48B6B19EF527718C6E15C /* Pods-ReusableDemo iOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-ReusableDemo iOS.modulemap"; sourceTree = ""; }; C7FEEBFF849983E3183C7BFE1C25E73F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - C9504196865F3C990C48E2735785DAAF /* Pods_ReusableDemo_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_ReusableDemo_tvOS.framework; path = "Pods-ReusableDemo tvOS.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + C9504196865F3C990C48E2735785DAAF /* Pods_ReusableDemo_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReusableDemo_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CB686EC9AF111FD8B0570725691219C2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; CFBAD7716370FCF78377CC43259E2DB0 /* Pods-ReusableDemo iOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-ReusableDemo iOS-umbrella.h"; sourceTree = ""; }; D2E8466DCD52BE65F107BAF60D975F28 /* StoryboardSceneBased.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StoryboardSceneBased.swift; path = Sources/Storyboard/StoryboardSceneBased.swift; sourceTree = ""; }; - D6364B0BC4181B760D63B01FE13EFA0B /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; path = README.md; sourceTree = ""; }; + D6364B0BC4181B760D63B01FE13EFA0B /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; D906BF925BD4D3B3E32DC4FBFD28B217 /* Pods-ReusableDemo iOS-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-ReusableDemo iOS-acknowledgements.markdown"; sourceTree = ""; }; DC0A06ABC80D9374C09CAC419E67EDB3 /* Pods-ReusableDemo tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReusableDemo tvOS.debug.xcconfig"; sourceTree = ""; }; ED66A027868D5B876E44283A1D2714D9 /* Pods-ReusableDemo tvOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-ReusableDemo tvOS-umbrella.h"; sourceTree = ""; }; @@ -431,12 +431,18 @@ attributes = { LastSwiftUpdateCheck = 0930; LastUpgradeCheck = 0930; + TargetAttributes = { + 833A3560B6F3546B84E92E9E7EAB6F13 = { + LastSwiftMigration = 1020; + }; + }; }; buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = 7DB346D0F39D3F0E887471402A8071AB; @@ -635,8 +641,7 @@ MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = NO; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.2; SYMROOT = "${SRCROOT}/../build"; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -700,7 +705,7 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -931,7 +936,7 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; diff --git a/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Reusable-iOS.xcscheme b/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Reusable-iOS.xcscheme index 87f1b87..ead5516 100644 --- a/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Reusable-iOS.xcscheme +++ b/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Reusable-iOS.xcscheme @@ -1,6 +1,6 @@ "https://github.com/AliSoftware/Reusable.git", :tag => s.version.to_s } - s.swift_version = '4.2' + s.swift_version = '5.0' s.subspec 'View' do |ss| ss.source_files = "Sources/View/*.swift"