【swift】カスタムビューをxibで作成して各ViewControllerで使い回す

# 概要
StoryboardでViewControllerのViewの一部が他のViewControllerでも同じレイアウトで表示している場合があります。その場合ViewをコピーしてViewControllerに貼り付けて利用したりしますが、それだとそのViewに変更を加えると複数利用しているため他のViewも変更しなくてはなりません。
そう行った場合、使い回せるViewをカスタムビューとしてxibで作成して利用することで、そのxibのみを変更すれば複数のViewでその変更が反映されるようになります。

# 実装方法
まずは、カスタムビューをxibで作成します。

![SampleView_xib.png](https://qiita-image-store.s3.amazonaws.com/0/194104/e267165a-f22e-e48c-8811-fb989c3a9052.png)
続いて、ViewControllerで、xibのカスタムビューをインスタンス化します。

```swift:ViewController.swift
class ViewController: UIViewController {

    weak var sampleView: UIView!
    
    override func loadView() {
        super.loadView()

        sampleView = UINib(nibName: "SampleView", bundle: Bundle.main).instantiate(withOwner: self, options: nil).first as? UIView
        sampleView.backgroundColor = .yellow
        view.addSubview(sampleView)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        sampleView.frame = CGRect.init(x: 100.0, y: 100.0, width: 100.0, height: 100.0)
    }

}
```
この時に、withOwnerでselfを指定しているので、xibで生成したlabelを@IBOutletで繋ぐことが出来ます。

```swift
UINib(nibName: "SampleView", bundle: Bundle.main).instantiate(withOwner: self, options: nil).first as? UIView
```

```swift:ViewController.swift
    weak var sampleView: UIView!
    @IBOutlet weak var label: UILabel!
    
    override func loadView() {
        super.loadView()

        sampleView = UINib(nibName: "SampleView", bundle: Bundle.main).instantiate(withOwner: self, options: nil).first as? UIView
        sampleView.backgroundColor = .yellow
        view.addSubview(sampleView)
        label.text = "あああ"
    }
```

■ビルド実行

![Simulator Screen Shot - iPhone XS - 2019-03-26 at 14.41.56.png](https://qiita-image-store.s3.amazonaws.com/0/194104/3bf85627-7ffe-fdab-ee6d-5ab9b2c49aae.png)

# カスタムビューを管理するクラスを生成する
ViewControllerでxibのViewをインスタンス化して使用するのは上記の方法ですが、多くの場合カスタムビューを管理するクラスを作成してxibとセットで利用したいと考えます。

その方法としては、withOwnerをカスタムビューを管理するクラスにします。

（SampleViewOwnerはSampleView.xibを管理するクラス）

```swift:SampleViewOwner.swift
class SampleViewOwner: NSObject {

    @IBOutlet weak var label: UILabel!
    var sampleView: UIView!
    
    override init() {
        super.init()
        
        sampleView = UINib(nibName: "SampleView", bundle: Bundle.main).instantiate(withOwner: self, options: nil).first as? UIView
        label.text = "いいい"
    }
}
```

```swift:ViewController.swift
class ViewController: UIViewController {
    
    var sampleViewOwner: SampleViewOwner!
    
    override func loadView() {
        super.loadView()

        sampleViewOwner = SampleViewOwner()
        sampleViewOwner.sampleView.backgroundColor = .yellow
        view.addSubview(sampleViewOwner.sampleView)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        sampleViewOwner.sampleView.frame = CGRect.init(x: 100.0, y: 100.0, width: 100.0, height: 100.0)
    }

}
```

こうすることで各ViewControllerでownerクラスをインスタンス化して使用すれば、xib上のlabel等の変更は、管理するownerクラスの方で行うことが出来ます。

■ビルド結果

![Simulator Screen Shot - iPhone XS - 2019-03-26 at 14.58.38.png](https://qiita-image-store.s3.amazonaws.com/0/194104/0854b5dc-2b90-1790-5e01-a874d7fb3d4a.png)