プロトコルとデリゲートのとても簡単なサンプルについて


デリゲートはよくわかりませんでした。だから、それをとても簡単に説明したいと思います。

Swiftです。

※注意。僕はエンジニアではないので、間違いなどあったらごめんなさい。ご指摘頂けるととても嬉しいです。)

どうでもよい追記:
=> エンジニアのお仕事頂けるようになったので、一応駆け出しエンジニアくらいにはなれました!(^^)/

どうしてデリゲートは分かりにくいのか。

僕はこう思います。

  • 登場人物がはっきりしていない。
  • 定義がはっきりしていない。

(はっきしているかもしれないけど、僕ははっきり理解できなかった。)

ちなみに、上の2つの曖昧なモノのうち、1つは今だに曖昧です。それでも大丈夫です。デリゲートとプロトコルについては理解できます。

登場人物だけおさえれば理解はできると思います。

まずは定義について

教科書(The Swift Programing Language)を読んでみますと、次のようにあります。

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.

簡単に言うと、こうです。

「デリゲートは、デザインパターンです。」

ここで僕は、生まれて初めて「デザインパターン」に出逢いました。

感動的な出逢いです。よく分からないものを調べたら、よく分からないものに出逢う。これ以上の探索をする気がいっきに失せます。

すでに諦めモードですが、せっかくなので、デザインパターンの定義をしらべてみました。個人的には一番すっきりしている定義は以下です。

A design pattern is a repeatable solution to a software engineering problem. (from techopedia)

ということで、デザインパタンの定義について雰囲気だけわかりました…。

分からない部分を無視してデリゲートを簡単に言えば、

「あるクラスは、他のクラスのインスタンスに、処理を任せることができる。」というようなこと。

登場人物について

本題に入ります。登場人物が分かれば、おしまいです。

登場人物は3人。

  • 処理を依頼する人
  • 依頼される人(代理人)
  • プロトコル

以上です。

例をつくります。

依頼するクラスを「Hoge」とします。
依頼される代理人クラスを「Piyo」とします。
そして、そのために使われるプロトコルを「Mochi」としておきます。

表示にすると以下のような感じです。

例)

依頼するクラス プロトコル 依頼されるクラス
Hoge Mochi Piyo
依頼する人 -> 代理人

もう、分かったようなものです。

コードを書いてみます。

Xcode6のplaygroundを使ってコードを書きます。これで説明は終わりです。

playground

// プロトコルを作る。
protocol Mochi {
    func sayHello() -> String
}

// 依頼人クラス
class Hoge {

    // ここで、プロトコルに従うクラスのインスタンスを用意する。
    var delegate: Mochi!
    func say() -> String {
        return delegate.sayHello()
    }
}

// 代理人クラス。クラスの後ろにプロトコルを書く。
class Piyo: Mochi {
    func sayHello() -> String {
        return "Hello, Piyopiyo"
    }
}

let hoge = Hoge()
let piyo = Piyo()
hoge.delegate = piyo    // 代理人を指定。
hoge.say()    // "Hello, Piyopiyo"

ポイントは、var delegate: Mochi!だと思います。(この「delegate」は任意の文字列で大丈夫です。)

改めて、なぜデリゲートが分かりづらいかと言うと。(僕が理解できなかったかと言うと。)

一般的なデリゲートの処理では、このvar delegate: SomeProtocol!が見えないところに存在しているからです。

例えば、キーボードを押し下げるというデリゲートの簡単なサンプルがあります。
http://qiita.com/mochizukikotaro/items/b35c93866fcc55e201f3

SomeViewController.swift

import UIKit

// まず、デリゲートプロトコルを宣言
class ViewController: UIViewController, UITextFieldDelegate {

    // テキストフィールドをアウトレット接続して
    @IBOutlet var textHoge : UITextField

    override func viewDidLoad() {
        super.viewDidLoad()

        // selfをデリゲートにする
        self.textHoge.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // selfをデリゲートにしているので、ここにデリゲートメソッドを書く
    func textFieldShouldReturn(textField: UITextField!) -> Bool {
        self.view.endEditing(true)
        return false
    }
}

登場人物は、

  • 代理人クラス:ViewController
  • 依頼人クラス:UITextField
  • プロトコル:UITextFieldDelegate

です。が、ここでUITextFieldの中身がどう書かれているかなんて普通見ません。素人は。中身はこうなっていました。

UITextField

class UITextField : UIControl, UITextInput, UIKeyInput, UITextInputTraits, NSObjectProtocol, NSCoding {
//中略
var delegate: UITextFieldDelegate! // default is nil. weak reference
//中略
}

だから、self.textHoge.delegate = selfと書けば、ちゃんと処理を委任できるんですね。

こんなことは、「べつに普通じゃん。簡単じゃん。」と言われれば、そうなのかもしれないですが、僕としては、

var delegate: UITextFieldDelegate!という記述を、自分の目で見ないと、どこに書いてあるのか把握できないと、納得感がないのです。

だから、その辺の参考書を読んでも、デリゲートとかプロトコルについて全然分かんないんです。そもそもデリゲートの説明で、プロトコルの説明なかったりしますし。

以上です。

ちなみに、上の例はデリゲート(プロトコル)を使わなくてもできます。

playground

class Hoge2 {    
    var delegate: Piyo2!
    func speak() -> String {
        return delegate.say()
    }
}

class Piyo2 {    
    func say() -> String {
        return "こんにちは!"
    }
}

var hoge2 = Hoge2()
var piyo2 = Piyo2()
hoge2.delegate = piyo2
hoge2.speak()