diff --git a/CHANGELOG.md b/CHANGELOG.md index a293617..71f54dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # CHANGELOG +## Unreleased + +### Breaking change + +* `static func loadFromNib(owner:)` of `NibOwnerLoadable` has been replaced by instance method `func loadNibContent()`. + This is more consistent and also avoids possible crashes when used with `UIView` subclasses not implementing non-required initializers `init()`/`init(frame:)`. + [@Skoti](https://github.com/Skoti) + [#40](https://github.com/AliSoftware/Reusable/pull/40) + +### Enhancements + +* Fixing documentation typos for `CollectionHeaderView` and `MyXIBIndexSquaceCell`. + [@Skoti](https://github.com/Skoti) + +* Fixing table view controller scene in Example project, to display cells above `UITabBar`. + [@Skoti](https://github.com/Skoti) + ## 3.0.1 * Fix `instantiate()` implementation on `StoryboardSceneBased` ViewControllers. diff --git a/Example/ReusableDemo/Base.lproj/Main.storyboard b/Example/ReusableDemo/Base.lproj/Main.storyboard index be34a00..63e17b7 100644 --- a/Example/ReusableDemo/Base.lproj/Main.storyboard +++ b/Example/ReusableDemo/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - - + + @@ -90,6 +90,7 @@ + diff --git a/Example/ReusableDemo/CollectionViewCells/CollectionHeaderView.swift b/Example/ReusableDemo/CollectionViewCells/CollectionHeaderView.swift index 2251cff..a1d3f90 100644 --- a/Example/ReusableDemo/CollectionViewCells/CollectionHeaderView.swift +++ b/Example/ReusableDemo/CollectionViewCells/CollectionHeaderView.swift @@ -16,7 +16,7 @@ import Reusable * It is also reusable and has a `reuseIdentifier` (as it's a CollectionViewCell * and it uses the CollectionView recycling mechanism) => it is `Reusable` * - * That's why it's annotated with the `NibOwnerLoadable` protocol, + * That's why it's annotated with the `NibReusable` protocol, * Which in fact is just a convenience typealias that combines * `NibLoadable` & `Reusable` protocols. */ diff --git a/Example/ReusableDemo/CollectionViewCells/MyXIBIndexSquaceCell.swift b/Example/ReusableDemo/CollectionViewCells/MyXIBIndexSquaceCell.swift index 67fd79e..59f0807 100644 --- a/Example/ReusableDemo/CollectionViewCells/MyXIBIndexSquaceCell.swift +++ b/Example/ReusableDemo/CollectionViewCells/MyXIBIndexSquaceCell.swift @@ -16,7 +16,7 @@ import Reusable * It is also reusable and has a `reuseIdentifier` (as it's a CollectionViewCell * and it uses the CollectionView recycling mechanism) => it is `Reusable` * - * That's why it's annotated with the `NibOwnerLoadable` protocol, + * That's why it's annotated with the `NibReusable` protocol, * Which in fact is just a typealias that combines * `NibLoadable` & `Reusable` protocols. */ diff --git a/Example/ReusableDemo/CustomViews/MyCustomWidget.swift b/Example/ReusableDemo/CustomViews/MyCustomWidget.swift index 407a90c..89ea381 100644 --- a/Example/ReusableDemo/CustomViews/MyCustomWidget.swift +++ b/Example/ReusableDemo/CustomViews/MyCustomWidget.swift @@ -26,9 +26,6 @@ class MyCustomWidget: UIView, NibOwnerLoadable { required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - MyCustomWidget.loadFromNib(owner: self) - } - override init(frame: CGRect) { - super.init(frame: frame) + self.loadNibContent() } } diff --git a/Example/ReusableDemo/TableViewCells/MyHeaderTableView.swift b/Example/ReusableDemo/TableViewCells/MyHeaderTableView.swift index 985e886..e2a35dd 100755 --- a/Example/ReusableDemo/TableViewCells/MyHeaderTableView.swift +++ b/Example/ReusableDemo/TableViewCells/MyHeaderTableView.swift @@ -22,6 +22,7 @@ final class MyHeaderTableView: UIView, NibOwnerLoadable { override init(frame: CGRect) { super.init(frame: frame) + self.loadNibContent() } required init?(coder aDecoder: NSCoder) { diff --git a/Example/ReusableDemo/TableViewController.swift b/Example/ReusableDemo/TableViewController.swift index bc6f627..572799a 100755 --- a/Example/ReusableDemo/TableViewController.swift +++ b/Example/ReusableDemo/TableViewController.swift @@ -27,7 +27,12 @@ final class TableViewController: UITableViewController { } override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let view = MyHeaderTableView.loadFromNib() + 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 } diff --git a/README.md b/README.md index 0aeaa41..cba1a73 100644 --- a/README.md +++ b/README.md @@ -297,17 +297,14 @@ final class MyCustomWidget: UIView, NibOwnerLoadable { … required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - MyCustomWidget.loadFromNib(owner: self) - } - override init(frame: CGRect) { - super.init(frame: frame) + self.loadNibContent() } } ``` Overriding `init?(coder:)` allows your `MyCustomWidget` custom view to load its content from the associated XIB `MyCustomWidget.xib` and add it as subviews of itself. -_💡 Note: overriding `init(frame:)`, even just to call `super.init(frame: frame)` might seems pointless, but seems necessary in some cases due to a strange issue with Swift and dynamic dispatch not being able to detect and call the superclass implementation all by itself: I've sometimes seen crashes when not implementing it explicitly, so better safe than sorry._ +_💡 Note: it is also possible to override `init(frame:)`, in order to be able to create an instance of that view programatically and call `loadNibContent()` to fill with views if needed. ## 3b. Instantiating a `NibLoadable` view @@ -322,8 +319,6 @@ let view3 = NibBasedRootView.loadFromNib() // and another one … ``` -> 💡 You could also use `MyCustomWidget.loadFromNib()` on a `NibOwnerLoadable` — the same way we just did on `NibLoadable` views above — to load them by code if needs be too. - --- diff --git a/Sources/View/NibOwnerLoadable.swift b/Sources/View/NibOwnerLoadable.swift index b1c861a..827b552 100644 --- a/Sources/View/NibOwnerLoadable.swift +++ b/Sources/View/NibOwnerLoadable.swift @@ -34,31 +34,24 @@ public extension NibOwnerLoadable { public extension NibOwnerLoadable where Self: UIView { /** - Returns a `UIView` object instantiated from nib - - - parameter owner: The instance of the view which will be your File's Owner - (and to which you want to add the XIB's views as subviews). - Defaults to a brand new instance if not provided. - - returns: A `NibOwnLoadable`, `UIView` instance + Adds content loaded from the nib to the end of the receiver's list of subviews and adds constraints automatically. */ - @discardableResult - static func loadFromNib(owner: Self = Self()) -> Self { + func loadNibContent() { let layoutAttributes: [NSLayoutAttribute] = [.top, .leading, .bottom, .trailing] - for view in nib.instantiate(withOwner: owner, options: nil) { + for view in Self.nib.instantiate(withOwner: self, options: nil) { if let view = view as? UIView { view.translatesAutoresizingMaskIntoConstraints = false - owner.addSubview(view) + self.addSubview(view) layoutAttributes.forEach { attribute in - owner.addConstraint(NSLayoutConstraint(item: view, + self.addConstraint(NSLayoutConstraint(item: view, attribute: attribute, relatedBy: .equal, - toItem: owner, + toItem: self, attribute: attribute, multiplier: 1, constant: 0.0)) } } } - return owner } }