[swift]4ステップで実装できるdelegate



こんにちは！

前回
> *[Swift]状態を共有して変化を伝播させるサンプル~didSetなど~*
 \(http://qiita.com/iKichiemon/items/c38fdc4b1a3f73f1f38e)


で、delegate関連の記事を書きましたが、

今回はもっと導入部分を書きます。


具体的には

 **「ユーザーがメールを送信する」** 

状況を想定して、４ステップで実装します。


1. 説明
2. 実装



## 1. 説明

delegateとは、なにかの機能を指し示しているのではなく
delegateという書き方を使いましょう、というデザインパターンです。

ネットで検索するとしばしば目にするのが
「delegateは処理を **移譲** するもの」という説明。


###もっと簡単に

ですが、これでは全然分からないので、

もっと簡単にdelegateを説明してみると、

クラス自身には機能をもたせず、

> *「誰かこれやって！」*

とお願いする書き方がdelegateです。

***

メール送信の例で言えば、

ユーザーがメールサーバーに送信をお願いし、その結果を表示したい時とか、
非同期で送信し、その完了イベントを通知したいときなどに利用できます。

> *メールサーバーに対して「このメールを送ったら教えてね！」とお願いする*

イメージになります。


###必要な実装は

* プロトコル
* ユーザークラス
* メールサーバークラス


| 実装するもの | ---------   | 名前 |
|:-----------:|:------------:|:------------:|
| メールを送信完了したら教える先         |       --> |     MailServerDelegate     |
| 完了イベントを受け取りたいユーザー     |       -->  |    User    |
| メールを送信して完了通知するメールサーバー       |        --> |     MailServer     |




## 2. 実装

まず、枠を作りましょう。

### STEP1. 登場するクラス・プロトコル
***
ユーザー。

``` swift
class User {
}
``` 

メールサーバー。

``` swift
class MailServer {
}
``` 

これはメール送信に関連するイベント。

``` swift
protocol MailServerDelegate {
}
``` 


### STEP2. delegateの仕組みを作る
***

それぞれの枠ができたので、
どこになにを持たせるのか、という連携部分を書いてみましょう。


ユーザーは、メール送信の完了イベントを受け取りたいので、
Delegateを実装させます。

こうすることで、

> 私がイベントをうけとります。

と指示できるようになります。

``` swift
class User: MailServerDelegate {

    /*
    * ボタンが押された時の処理
    */
    func sendButtonPushed() {
    }
}
``` 

メールサーバーは、メール送信処理と、イベントの通知先を持ちます。

``` swift
class MailServer {
   
    // イベントを通知する先
    weak var delegate: MailServerDelegate?

    /*
    * メールを送信する処理
    */
    func sendMail(message: String) {
    }
}
``` 

こちらはメール送信のイベント通知先。
どんなイベントをしてほしいかを書く。

``` swift

protocol MailServerDelegate {

    /*
    * 送信した時のイベント
    * 「メール送信成功しました！」
    * 「メール送信失敗しました...」
    */
    func onSuccessSendMail() -> Vold
    func onFailureSendMail() -> Vold
}
``` 


### STEP3. 機能実装
***

ゆるーい連携部分ができたので、
どういう処理をさせていくかを簡単に書きましょう

メールサーバーは、
メール送信の具体的な中身を実装する。

メール送信が呼ばれるのは、
[送信]ボタンが押されて、ユーザーがメール送信をお願いした時。

``` swift

class MailServer {

    // イベントを通知する先
    weak var delegate: MailServerDelegate?

    /*
    * メールを送信する処理
    * 「あ、このメッセージを送るんですね、わかりました。メール送信します。
    *   完了したらdelegateに知らせますね。」
    */
    func sendMail(message: String) -> Void{
        // 非同期メール送信処理を書く
        if 成功 {
            self.delegate?.onSuccessSendMail()
        } else {
            self.delegate?.onFailureSendMail()
        }
    }
}
``` 

### STEP4. 仕上げ
***

最後の仕上げです。
Userにdelegateを継承させて実装します！

delegateを継承させること → イベントを受け取る準備。
mailServer.delegate = self　→　「イベントは私が処理します」と伝える宣言


ユーザーは、[送信]ボタンが押されたら、メールサーバーに送信依頼をします。

その結果は、非同期などであればいつ帰ってくるかわからないので、      
実装したMailServerDelegateの処理が呼ばれるまで待ちます。

``` swift

class User: MailServerDelegate {

    let mailServer: MailServer

    init(){
        self.mailServer = MailServer()
        self.mailServer.delegate = self // 送信結果はselfに教えてね。
    }

    /*
    * ボタンが押された時の処理
    */
    func sendButtonPushed(message: String){
        // メールを送信する。送信の結果は、delegate経由で受け取る。
        self.mailServer.sendMail(message)
    }

    // 送信結果。mailServerからコールされる
    func onSuccessSendMail() -> Vold {
        print("success!")
    }
    func onFailureSendMail() -> Vold {
        print("failure..")
    }
}

``` 


***

## 書いたものまとめ

いかがでしたでしょうか。

なかなかイメージしづらいdelegateですが、
少しでもお力になれれば幸いです。


``` swift
class User: MailServerDelegate {

    let mailServer: MailServer

    init(){
        self.mailServer = MailServer()
        self.mailServer.delegate = self
    }

    /*
    * ボタンが押された時の処理
    */
    func sendButtonPushed(message: String){
        // メールを送信する。送信の結果は、delegate経由で受け取る。
        self.mailServer.sendMail(message)
    }

    // 送信結果。mailServerからコールされる
    func onSuccessSendMail() -> Vold {
        print("success!")
    }
    func onFailureSendMail() -> Vold {
        print("failure..")
    }
}

protocol MailServerDelegate {

    /*
    * 送信した時のイベント
    * 「メール送信成功しました！」
    * 「メール送信失敗しました...」
    */
    func onSuccessSendMail() -> Vold
    func onFailureSendMail() -> Vold
}

// メールを送信して、delegateに対して結果を知らせます。
class MailServer {

    // イベントを通知する先
    weak var delegate: MailServerDelegate?

    /*
    * メールを送信する処理
    * 「あ、このメッセージを送るんですね、わかりました。メール送信します。
    *   完了したらdelegateに知らせますね。」
    */
    func sendMail(message: String) -> Void{
        // 非同期メール送信処理を書く
        if 成功 {
            self.delegate?.onSuccessSendMail()
        } else {
            self.delegate?.onFailureSendMail()
        }
    }
}
```