CustomView上のButtonから別クラスにアクションを設定する方法


<code>swift</code>

<p><code>CustomView</code>を作成し、別の<code>ViewContoroller</code>上に表示させたは良いものの、<code>CustomView</code> 上に設置したButtonのアクションをどうやってそのVCで発動させるかでつまずいたので、その方法をざっくり解説します。</p>
<p>結論、<code>protocol</code>と<code>delegate</code>を使用します。</p>

<h2>流れ</h2>
<ul>
<li>前提確認</li>
<li>protocol宣言</li>
<li>処理を発動するクラスでの記述</li>
<li>処理を行うクラスでの記述</li>
<li>それぞれのコードと画面</li>
<li>終わりに</li>
</ul>

<h2>前提確認</h2>
MacOS Catalina 10.15.4
Xcode 12.1
Swift version 5

<code>CustomView</code>(これに接続するVCを<code>CustomViewVC</code>と命名)で上下矢印の<code>UIButton</code>を用意し、別のVC(<code>MainVC</code>と命名)上にある<code>UILabel</code>の値を変化させます。変化のさせ方は「上矢印を押せば+1、下矢印を押せば-1」(以下、処理)とします。
<code>protocol</code>と<code>delegate</code>を使用しますが、<code>CustomViewVC</code>が処理を発動させるクラス、<code>MainVC</code>が処理を実際に行うクラスになります。
尚、<code>CustomViewVC</code>の作成は主旨から外れますので他の記事に譲ります。

<h2>protocol宣言</h2>
宣言場所はどのクラスでも大丈夫ですが、<code>import xxx</code>と<code>class xxx</code>の間に書くようにしましょう。
ここでは<code>MainVC</code>に書くことにします。

```swift:MainVC
import UIKit

@objc protocol CustomViewDelegate : NSObjectProtocol {
    
    func plus()
    
    func minus()
    
}

class MainViewController: UIViewController{
```

<h2>処理を発動するクラスでの記述</h2>
<code>protocol</code>型の変数を宣言します。変数名は<code>delegateTest</code>とします。
ここで<code>IBOutlet</code>で接続させるのがミソです。

```swift:CustomViewVC
@IBOutlet var delegateTest: CustomViewDelegate?
```

上下矢印<code>Button</code>をそれぞれ<code>IBAction</code>接続し、その中に+1と-1の処理を発動させます。
(発動だけで、ここで処理は行われません)

```swift:CustomViewVC
@IBAction func plus() {
        delegateTest?.plus()
    }
    
    @IBAction func minus() {
        delegateTest?.minus()
    }
```

<h2>処理を行うクラスでの記述</h2>
まずは、<code>protocol</code>を継承させます。

```swift:MainVC
class MainViewController: UIViewController, CustomViewDelegate {
```

次に、<code>MainVC</code>に<code>CustomView</code>から<code>delegate</code>を接続させます。
これを行うことで<code>CustomView</code>で発動させた処理を、<code>MainVC</code>にて行うことができます。
その接続方法ですが、<code>CustomView</code>を表示させているUIViewをクリックし、インスペクタバー の「Show the Connections inspector」(一番右のアイコン)を見ます。
すると、先ほどIBOutletで宣言した<code>delegate</code>変数が表示されているので、<code>MainVC</code>にドラックして接続させます。

あとは行う処理を内容を記述すればOKです。

```swift:MainVC
    func plus() {
        number += 1
        label.text = "\(number)"
    }
    
    func minus() {
        number -= 1
        label.text = "\(number)"
    }
```

<h2>それぞれコードと画面</h2>
```swift:CustomViewVC
import UIKit

class CustomView: UIView {
    
    @IBOutlet var plusBtn: UIButton!
    @IBOutlet var minusBtn: UIButton!

    
    @IBOutlet var delegateTest: CustomViewDelegate?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        loadNib()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        loadNib()
        //fatalErrorがデフォルトで入っていますが消さないとエラーになってしまうので注意してください！
    }
    
    func loadNib() {
        //CustomViewの部分は各自作成したXibの名前に書き換えてください
        let view = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)?.first as! UIView
        view.frame = self.bounds
        self.addSubview(view)
    }

    @IBAction func plus() {
        delegateTest?.plus()
    }
    
    @IBAction func minus() {
        delegateTest?.minus()
    }
```

![WechatIMG851.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843253/daf7ce8b-073a-5cb6-ad9b-ccf0ba4c8b8b.png)


```swift:MainViewController
import UIKit

@objc protocol CustomViewDelegate : NSObjectProtocol {
    
    func plus()
    
    func minus()
    
}

class MainViewController: UIViewController, CustomViewDelegate {
    
  
    @IBOutlet weak var testView: CustomView!
    @IBOutlet weak var label: UILabel!
    
    var number = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        }
    
    func plus() {
        number += 1
        label.text = "\(number)"
    }
    
    func minus() {
        number -= 1
        label.text = "\(number)"
    }
    
  
}
```
![WechatIMG852.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843253/f7054af2-b728-2442-63d5-002e3d893662.png)


<h2>終わりに</h2>
<code>CustomView</code>は便利だと思うのですが、私自身今まで使ったことがなく、表示させたは良いものの、使い勝手悪いように感じましたので、ここで使い方の一つを解説させて頂きました。
<code>protocol</code>の中身がほぼないのは良くないかもしれませんが、あくまで<code>CustomView</code>の処理を別VCで行うことを主旨とするため、簡潔にさせて頂きました。
初めての投稿ですので、至らない点あるかと思いますが、何かあればご指摘・アドバイス頂けると幸いです。