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

  • 126
    Like
  • 8
    Comment
More than 1 year has passed since last update.

こんにちは!

前回

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

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

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

具体的には

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

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

  1. 説明
  2. 実装

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()
        }
    }
}