Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
5 changes: 3 additions & 2 deletions Example/ReusableDemo/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="7fF-Ae-xTS">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="7fF-Ae-xTS">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
Expand Down Expand Up @@ -90,6 +90,7 @@
<outlet property="delegate" destination="Spa-tB-Bt1" id="iqn-sB-Tfo"/>
</connections>
</tableView>
<extendedEdge key="edgesForExtendedLayout" top="YES"/>
<tabBarItem key="tabBarItem" title="TableView" id="C3o-Lt-Bjj"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="XEN-tN-mKX" userLabel="First Responder" sceneMemberID="firstResponder"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
5 changes: 1 addition & 4 deletions Example/ReusableDemo/CustomViews/MyCustomWidget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ final class MyHeaderTableView: UIView, NibOwnerLoadable {

override init(frame: CGRect) {
super.init(frame: frame)
self.loadNibContent()
}

required init?(coder aDecoder: NSCoder) {
Expand Down
7 changes: 6 additions & 1 deletion Example/ReusableDemo/TableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
9 changes: 2 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.

---


Expand Down
19 changes: 6 additions & 13 deletions Sources/View/NibOwnerLoadable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}