【swift】イラストで分かる！具体的なDelegateの使い方。

[ディップAdventCalendar2016](http://qiita.com/advent-calendar/2016/dip-dev)、23日目です。(｡･ω･)ﾉ

****
![kaisou９.png](https://qiita-image-store.s3.amazonaws.com/0/146629/d680edba-66b2-4c51-31c1-7eb07ae2c105.png)

※Delegateの書き方を理解するに重点を置いてますので、Delegateの本来の使い方を知りたい方には向いておりません。
あくまでも取っ掛かりという目的で閲覧くださいm(_ _)m

**swift初心者の多くは苦戦するDelegate。**
まず最初にぶつかる壁と言っても良いでしょう。

私もその１人で、
分かりにくい分たくさんのDelegateの記事が存在していますが、
**ありとあらゆる「わかりやすい！簡単！Delegate」の記事を見てもなかなかピンときませんでした..orz**
（私の理解力の問題ですが..）

ということで、
**世に溢れているわかりやすいDelegateの説明を見ても理解できなかった私が、
イラストを使ってさらにわかりやすく、Delegateの基本を書いていきたいと思います。**

# 1.そもそもなぜ理解できないのか？

まず、そもそもなぜDelegateの理解が難しいのか。

端的に言いますと、結局のところ
**「で、何ができるの？😰😰」**
**「使いどころがわからない..😰😰」**
ってところに尽きるのかなと思います。

それだと結局、
**「サンプルコード見て書き方は分かったよ、うん（でも自分で流用できない）」**
**＝ 理解できていない**
となってしまうので、そこを紐解く必要があります。

# 2.Delegateとは？
[プロトコルとデリゲートのとても簡単なサンプルについて](http://qiita.com/mochizukikotaro/items/a5bc60d92aa2d6fe52ca)
こちらの記事を参考にさせていただきますと、

> Delegation is a design pattern that enables a class or structure to hand off(or delegate) some of its responsibilities to an instance of another type.
（The Swift Programing Language記載）

＝『デリゲートは、デザインパターンです。』

「ん、デザインパターンって何😰」..となるので、ここは割愛。

結局のところDelegateは、
**「あるクラスは、他のクラスのインスタンスに、処理を任せることができる。」**
もの、なのですが、

とりあえず**「２つのクラス間で処理を跨ぐんだな😃」**くらいで大丈夫です。

# 3.具体例
まずは、具体的な使い方を見てみようと思います。
今回はよりDelegateの書き方がピンとくるように、
**「Delegateを使った場合」「使わなかった場合」**の２パターンで説明しようと思います。

## 作るもの
こんなの。
![kaisou.png](https://qiita-image-store.s3.amazonaws.com/0/146629/71c1e551-6961-5ebb-3b20-c9950f6244e1.png)

構造としてはこのような感じです。
このぺージの親はViewControllerですね。

![kaisou２.png](https://qiita-image-store.s3.amazonaws.com/0/146629/b2c4980f-4a52-d079-46c0-2c5d052e0fe4.png)

## 階層の違い
この２つのパターンは今回の場合クラス構成が一番の相違点で、
tableViewが親のViewControllerのクラスで処理が書かれているか否かに違いがあります。

### ■Delegateなし
![kaisou３.png](https://qiita-image-store.s3.amazonaws.com/0/146629/80dc3abe-113f-e0ca-d6c1-acd4bc10b427.png)

### ■Delegateあり
![kaisou４.png](https://qiita-image-store.s3.amazonaws.com/0/146629/860323be-18d5-a60a-05c9-4f0f908884ef.png)

## 押さえておく点
※解説の前に押さえておくべきこと。

今回のサンプルは
tableViewCellをタップした際に**ページ遷移する**。
つまり、そのぺージから別のぺージに移動する、ということです。
ということは、
そのぺージを作る一番親が**別のページに遷移する**を実行しなければなりません。
**ここが重要です。**

## ソースの違い
各々のDelegateが絡んでいる部分の書き方の違う部分をとりあえず記載。
**下記２つはまったく同じ処理をしている部分です。**

具体的には、`didSelectRowAt indexPath:`の書き方に違いがあります。
`didSelectRowAt indexPath:`とはTableView上のcellがタップされた際に呼ばれるメソッドです。

### ■Delegateなし

```.swift:親（ViewController）
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!

    //〜省略〜
    
    // MARK: - UITableViewDelegate
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        
        guard let url = URL(string: "https://www.youtube.com/watch?v=GNIkcjccZlw") else {
            return
        }
        
        if UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.open(url, options: [], completionHandler: nil)
        }
    }
}
```

### ■Delegateあり
```.swift:子（DelegateTableView）
class DelegateTableView: UITableView, UITableViewDataSource, UITableViewDelegate {

    //delegateを設定
    var testdelegate: TestDelegate?

    //〜省略〜

    // MARK: - UITableViewDelegate
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.deselectRow(at: indexPath, animated: true)

        self.testdelegate?.test()
    }
}
```
```.swift:Delegate
protocol TestDelegate: class {

    func test()
}
```
```.swift:親（ViewController）
class ViewController: UIViewController, TestDelegate {

    @IBOutlet weak var delegateTableView: DelegateTableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //子（DelegateTableView）の設定しているdelegateを自身にもセット
        delegateTableView.testdelegate = self
    }
    
    func test() {
        guard let url = URL(string: "https://www.youtube.com/watch?v=GNIkcjccZlw") else {
            return
        }
        
        if UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.open(url, options: [], completionHandler: nil)
        }
    }
}
```

## イメージ図
上の処理は絵で表すとこんな状況。
### ■Delegateなし
![kaisou５.png](https://qiita-image-store.s3.amazonaws.com/0/146629/e8d537ac-bef7-4bc3-0cca-6f068cc819e8.png)


### ■Delegateあり
![kaisou６.png](https://qiita-image-store.s3.amazonaws.com/0/146629/a2a08b37-e6c6-40f3-0429-703b43596d2d.png)
![kaisou７.png](https://qiita-image-store.s3.amazonaws.com/0/146629/aa344798-cc13-93aa-bda5-10d80f700fc2.png)
![kaisou8.png](https://qiita-image-store.s3.amazonaws.com/0/146629/ede928ae-f56f-38d2-0ef4-147d36f08e57.png)


## ポイント
### 変数の受け渡し

```.swift:子（DelegateTableView）
//delegateを設定
var testdelegate: TestDelegate?
```
```.swift:親（ViewController）
//子（DelegateTableView）の設定しているdelegateを自身にもセット
delegateTableView.testdelegate = self
```

別クラスで定義されている変数を自身も持つことで
自分がそのdelegateを処理することができるようになります。
この辺りの受け渡しはミスしないように注意してください。

※この=selfは`TestDelegate `を継承しないとErrorとなり、
`delegateTableView.testdelegate = self as! TestDelegate `と補完しようとするのでこちらも注意です。

### protocol

```.swift:Delegate
protocol TestDelegate: class {

    func test()
}
```
`protocol (名前)`と書くことで、継承できるようになります。
<img width="431" alt="朝.png" src="https://qiita-image-store.s3.amazonaws.com/0/146629/7b5d35bb-f1dc-c28d-27e5-6c8204d35f59.png">

また、もともとswiftに備わっている、`UITableViewDelegate`は、
継承した際、`cellForRowAt indexPath:`、`numberOfRowsInSection section:`の２つのメソッドを書かなければ
<img width="432" alt="スクリーンショット 2016-12-23 18.15.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/146629/2eaf0b3b-d3ec-cb23-55ae-2c4cc2108d2e.png">
このようなエラーをはきますよね、

これと同様に、上記の例だと、
`testDelegate`を継承したクラスで`func test()`を書かなければエラーとなります。

#### 補足
処理を追いやすくする手として、`extension`で書くことを検討するのもありです。

```swift
class ViewController: UIViewController {
    @IBOutlet weak var delegateTableView: DelegateTableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //子（DelegateTableView）の設定しているdelegateを自身にもセット
        delegateTableView.testdelegate = self
    }
}

extension ViewController: TestDelegate {
func test() {
        guard let url = URL(string: "https://www.youtube.com/watch?v=GNIkcjccZlw") else {
            return
        }
        
        if UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.open(url, options: [], completionHandler: nil)
        }
    }
}
```

### 処理の場所
先ほど述べた「押さえておく点」の通り、
画面が遷移する処理である、

```.swift
guard let url = URL(string: "https://www.youtube.com/watch?v=GNIkcjccZlw") else {
    return
}
        
if UIApplication.shared.canOpenURL(url) {
    UIApplication.shared.open(url, options: [], completionHandler: nil)
}
```

の処理はViewControllerに記載しています。
そこはDelegate使う使わないに限らず変わらないです。


#4.まとめ
今回は少しでもわかりやすいようにDelegate有無の書き方で分けてみましたが、
delegateを使う大きなメリットは

* 移譲先を意識する必要がない
* 再利用ができる

なので、メリットの実感はあまりないサンプルかもしれません。笑
が、少しでも参考になれば幸いです。 

ご指摘あればコメントよろしくお願いします。