こんにちは!
前回
[Swift]状態を共有して変化を伝播させるサンプル~didSetなど~
(http://qiita.com/iKichiemon/items/c38fdc4b1a3f73f1f38e)
で、delegate関連の記事を書きましたが、
今回はもっと導入部分を書きます。
具体的には
「ユーザーがメールを送信する」
状況を想定して、4ステップで実装します。
- 説明
- 実装
1. 説明
delegateとは、なにかの機能を指し示しているのではなく
delegateという書き方を使いましょう、というデザインパターンです。
ネットで検索するとしばしば目にするのが
「delegateは処理を 移譲 するもの」という説明。
もっと簡単に
ですが、これでは全然分からないので、
もっと簡単にdelegateを説明してみると、
クラス自身には機能をもたせず、
「誰かこれやって!」
とお願いする書き方がdelegateです。
メール送信の例で言えば、
ユーザーがメールサーバーに送信をお願いし、その結果を表示したい時とか、
非同期で送信し、その完了イベントを通知したいときなどに利用できます。
メールサーバーに対して「このメールを送ったら教えてね!」とお願いする
イメージになります。
必要な実装は
- プロトコル
- ユーザークラス
- メールサーバークラス
| 実装するもの | --------- | 名前 | 
|---|---|---|
| メールを送信完了したら教える先 | --> | MailServerDelegate | 
| 完了イベントを受け取りたいユーザー | --> | User | 
| メールを送信して完了通知するメールサーバー | --> | MailServer | 
2. 実装
まず、枠を作りましょう。
STEP1. 登場するクラス・プロトコル
ユーザー。
class User {
}
メールサーバー。
class MailServer {
}
これはメール送信に関連するイベント。
protocol MailServerDelegate {
}
STEP2. delegateの仕組みを作る
それぞれの枠ができたので、
どこになにを持たせるのか、という連携部分を書いてみましょう。
ユーザーは、メール送信の完了イベントを受け取りたいので、
Delegateを実装させます。
こうすることで、
私がイベントをうけとります。
と指示できるようになります。
class User: MailServerDelegate {
    /*
    * ボタンが押された時の処理
    */
    func sendButtonPushed() {
    }
}
メールサーバーは、メール送信処理と、イベントの通知先を持ちます。
class MailServer {
   
    // イベントを通知する先
    weak var delegate: MailServerDelegate?
    /*
    * メールを送信する処理
    */
    func sendMail(message: String) {
    }
}
こちらはメール送信のイベント通知先。
どんなイベントをしてほしいかを書く。
protocol MailServerDelegate {
    /*
    * 送信した時のイベント
    * 「メール送信成功しました!」
    * 「メール送信失敗しました...」
    */
    func onSuccessSendMail() -> Vold
    func onFailureSendMail() -> Vold
}
STEP3. 機能実装
ゆるーい連携部分ができたので、
どういう処理をさせていくかを簡単に書きましょう
メールサーバーは、
メール送信の具体的な中身を実装する。
メール送信が呼ばれるのは、
[送信]ボタンが押されて、ユーザーがメール送信をお願いした時。
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の処理が呼ばれるまで待ちます。
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ですが、
少しでもお力になれれば幸いです。
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()
        }
    }
}