プロトコルとデリゲートを書く順番と考え方


## 導入

サンプルコードには **ViewController** と **ModalView** が登場します。

ここでは **ViewController** が **ModalView** を持っているため、
**ViewController** の側から、 **ModalView** の持つ値を変更することができます。

ですが逆に **ModalView** が **ViewController** の持つ値を変更することはできません。

それを出来るようにするために、
プロトコルとデリゲートの設定を書いていきます。

## 手順を簡単に説明

まずサンプルコードと簡単な手順の説明です。

**ModalView**
ViewControllerからモーダルで遷移するView。
TextFieldを持っていて、モーダルを閉じるときそこに書かれている値をViewControllerのプロパティに反映させたい。

```swift
@objc protocol ModalViewDelegate {
	// 1. protocolの定義
	
	func modalView(text: String)
	// 6. 使いたいViewControllerのメソッド（5と同じもの）を定義
}

class ModalView: UIView {
	weak var customDelegate: ModalViewDelegate?
	// 2. ModalViewのプロパティを設定

	var textField = UITextField()

	func close() {
		customDelegate?.modalView(textField.text)
		// 7. ViewControllerのメソッドを実際に使う
	}
}

```

**ViewController**
labelとmodalViewを持っている。
modalViewからlabelの値を操作してもらいたい。

```swift
class ViewController: UIViewController, ModalViewDelegate {
	// 3. ViewControllerにModalViewDelegateを実装
	
	let label = UILabel()

	func showModal() {
		let modalView = ModalView()
		modalView.customDelegate = self
		// 4. modalViewのcustomDelegateプロパティにself(ViewController)を定義
	}
	
	func modalView(text: String) {
		label.text = text
	}
	// 5. ModalViewに使ってほしいメソッドを定義

}
```

## 手順を順番に説明

以下、一つ一つ手順を説明をしていきます。



1. protocolの定義

	ModalViewにprotocol自体を定義します。

	```swift
	@objc protocol ModalViewDelegate {
		// 1. protocolの定義
	}
	```
	
	まだ中身はなくても大丈夫です。
	　



2. ModalViewのプロパティを設定

	**ViewController** の値を変更するためには、
	**ModalView** が **ViewController** を持っていなくてはいけません。
	
	そのため **ModalView** に対し、
	**ViewController** を入れるべき、 **ModalViewDelegate?** 型のプロパティを定義します。

	```swift
	class ModalView: UIView {
		weak var customDelegate: ModalViewDelegate?
		// 2. ModalViewのプロパティを設定
	}
	```
	　

3. ViewControllerにModalViewDelegateを継承する
	先ほど **ModalView** に **ModalViewDelegate?** 型のプロパティを設定しましたが、
	**ViewController** は **ModalViewDelegate** 型ではないので、このままではプロパティに持てません。
	
	なので **ViewController** に **ModalViewDelegate** プロトコルを実装します。
	
	```swift
	class ViewController: UIViewController, ModalViewDelegate {
		// 3. ViewControllerにModalViewDelegateを実装
	}
	```
	　

4. modalViewのcustomDelegateプロパティにself(ViewController)を定義

	そして **ViewController** から **modalView** のcustomDelegateプロパティに **self** を設定します。
	
	ここでいう **self** は **ViewController** のことですね。

	```seift
	func showModal() {
		let modalView = ModalView()
		modalView.customDelegate = self
		// 4. modalViewのcustomDelegateプロパティにself(ViewController)を定義
	}
	```
	これで **ModalView** がプロパティに **ViewController** を持ち、
	**ViewController** のメソッドを使うことができるようになりました。
	　

5. ModalViewに使ってほしいメソッドを定義

	さらに **ModalView** に使ってほしいメソッドを **ViewController** に定義します。

	```swift
	func modalView(text: String) {
		label.text = text
	}
	// 5. ModalViewに使ってほしいメソッドを定義
	```
	　

6. 使いたいViewControllerのメソッド（5と同じもの）を定義

	さきほど **ViewController** に定義したメソッドを **ModalViewDelegate** の中にも書く必要があるので以下のように書いておきましょう。

	```swift
	@objc protocol ModalViewDelegate {
	// 1. protocolの定義
	
		func modalView(text: String)
		// 6. 使いたいViewControllerのメソッド（5と同じもの）を定義
	}
	```
	　

7. ViewControllerのメソッドを実際に使う

	これでようやく **ModalView** から **ViewController** のメソッドを使うことができるようになりました。

	なのでViewControllerの持つ値を変更したいところで、
	 **ModalView** のプロパティであるcustomDelegate?（中身は **ViewController**）の、modalView(text) メソッドを使用します。

	そうすることで **ViewController** のメソッドを、引数を持って呼び出すことができ、
	そのメソッド内で **ViewController** の持つ値を変更することができました。

	```swift
	func close() {
		customDelegate?.modalView(textField.text)
		// 7. ViewControllerのメソッドを実際に使う
	}
	```
	　

## weak varについて

ここまででプロトコルとデリゲートについて、やっていることや設定の手順は理解できたと思います。

ですがここで **ViewController** と **ModalView** は相互に持ち合う（参照し合う）という、通常よくないことが起きてしまっています。

---

まず、相互に参照し合うことがなぜ良くないのかという話からしましょう。

iPhoneアプリにはメモリという作業領域があります。
メモリは容量がいっぱいになるとアプリが落ちてしまうので、使わないものは作業領域から消すことが重要になります。

そこでswiftではインスタンスがあると、その分メモリを専有してしまうため、使わないときは自動でメモリ領域から消してくれます。

このとき、使っている使っていないをどう判断しているかというと、
**参照されているかされていないか**で判断しているのです。

なので、相互に参照し合っているというのは、常にメモリ領域をしてしまうため、良くないということなんですね。

---

その相互参照を解決しているのが **ModalView**のプロパティ宣言にある **weak** です。

```swift
weak var customDelegate: ModalViewDelegate?
```
**weak** は **弱参照** とも呼ばれ、
通常の定義（varやlet）とは対称的に強参照とも呼ばれます。

さきほど **参照されているかされていないか** で判断すると言ったのですが、
具体的には、強参照があると **参照カウント**（参照されている数）が増え、この参照カウントが1以上のときは、参照されているとみなされます。

そして、弱参照はこの **参照カウント** を増やしません。

つまり、強参照がなく、弱参照のみになると、インスタンスは破棄され、メモリを空けてくれる、ということなんですね。


デリゲートは性質上、相互参照が常に起こってしまうので、
このように片方は **弱参照** を用いることが慣習となっています。