LoginSignup
63
60

More than 5 years have passed since last update.

プロトコルとデリゲートを書く順番と考え方

Last updated at Posted at 2015-08-15

導入

サンプルコードには ViewControllerModalView が登場します。

ここでは ViewControllerModalView を持っているため、
ViewController の側から、 ModalView の持つ値を変更することができます。

ですが逆に ModalViewViewController の持つ値を変更することはできません。

それを出来るようにするために、
プロトコルとデリゲートの設定を書いていきます。

手順を簡単に説明

まずサンプルコードと簡単な手順の説明です。

ModalView
ViewControllerからモーダルで遷移するView。
TextFieldを持っていて、モーダルを閉じるときそこに書かれている値をViewControllerのプロパティに反映させたい。

@objc protocol ModalViewDelegate {
    // 1. protocolの定義

    func modalView(text: String)
    // 6. 使いたいViewControllerのメソッド(5と同じもの)を定義
}

class ModalView: UIView {
    weak var customDelegate: ModalViewDelegate?
    // 2. ModalViewのプロパティを設定

    var textField = UITextField()

    func close() {
        customDelegate?.modalView(textField.text)
        // 7. ViewControllerのメソッドを実際に使う
    }
}

ViewController
labelとmodalViewを持っている。
modalViewからlabelの値を操作してもらいたい。

class ViewController: UIViewController, ModalViewDelegate {
    // 3. ViewControllerにModalViewDelegateを実装

    let label = UILabel()

    func showModal() {
        let modalView = ModalView()
        modalView.customDelegate = self
        // 4. modalViewのcustomDelegateプロパティにself(ViewController)を定義
    }

    func modalView(text: String) {
        label.text = text
    }
    // 5. ModalViewに使ってほしいメソッドを定義

}

手順を順番に説明

以下、一つ一つ手順を説明をしていきます。

  1. protocolの定義

    ModalViewにprotocol自体を定義します。

    @objc protocol ModalViewDelegate {
        // 1. protocolの定義
    }
    

    まだ中身はなくても大丈夫です。
     

  2. ModalViewのプロパティを設定

    ViewController の値を変更するためには、
    ModalViewViewController を持っていなくてはいけません。

    そのため ModalView に対し、
    ViewController を入れるべき、 ModalViewDelegate? 型のプロパティを定義します。

    class ModalView: UIView {
        weak var customDelegate: ModalViewDelegate?
        // 2. ModalViewのプロパティを設定
    }
    

     

  3. ViewControllerにModalViewDelegateを継承する
    先ほど ModalViewModalViewDelegate? 型のプロパティを設定しましたが、
    ViewControllerModalViewDelegate 型ではないので、このままではプロパティに持てません。

    なので ViewControllerModalViewDelegate プロトコルを実装します。

    class ViewController: UIViewController, ModalViewDelegate {
        // 3. ViewControllerにModalViewDelegateを実装
    }
    

     

  4. modalViewのcustomDelegateプロパティにself(ViewController)を定義

    そして ViewController から modalView のcustomDelegateプロパティに self を設定します。

    ここでいう selfViewController のことですね。

    func showModal() {
        let modalView = ModalView()
        modalView.customDelegate = self
        // 4. modalViewのcustomDelegateプロパティにself(ViewController)を定義
    }
    

    これで ModalView がプロパティに ViewController を持ち、
    ViewController のメソッドを使うことができるようになりました。
     

  5. ModalViewに使ってほしいメソッドを定義

    さらに ModalView に使ってほしいメソッドを ViewController に定義します。

    func modalView(text: String) {
        label.text = text
    }
    // 5. ModalViewに使ってほしいメソッドを定義
    

     

  6. 使いたいViewControllerのメソッド(5と同じもの)を定義

    さきほど ViewController に定義したメソッドを ModalViewDelegate の中にも書く必要があるので以下のように書いておきましょう。

    @objc protocol ModalViewDelegate {
    // 1. protocolの定義
    
        func modalView(text: String)
        // 6. 使いたいViewControllerのメソッド(5と同じもの)を定義
    }
    

     

  7. ViewControllerのメソッドを実際に使う

    これでようやく ModalView から ViewController のメソッドを使うことができるようになりました。

    なのでViewControllerの持つ値を変更したいところで、
    ModalView のプロパティであるcustomDelegate?(中身は ViewController)の、modalView(text) メソッドを使用します。

    そうすることで ViewController のメソッドを、引数を持って呼び出すことができ、
    そのメソッド内で ViewController の持つ値を変更することができました。

    func close() {
        customDelegate?.modalView(textField.text)
        // 7. ViewControllerのメソッドを実際に使う
    }
    

     

weak varについて

ここまででプロトコルとデリゲートについて、やっていることや設定の手順は理解できたと思います。

ですがここで ViewControllerModalView は相互に持ち合う(参照し合う)という、通常よくないことが起きてしまっています。


まず、相互に参照し合うことがなぜ良くないのかという話からしましょう。

iPhoneアプリにはメモリという作業領域があります。
メモリは容量がいっぱいになるとアプリが落ちてしまうので、使わないものは作業領域から消すことが重要になります。

そこでswiftではインスタンスがあると、その分メモリを専有してしまうため、使わないときは自動でメモリ領域から消してくれます。

このとき、使っている使っていないをどう判断しているかというと、
参照されているかされていないかで判断しているのです。

なので、相互に参照し合っているというのは、常にメモリ領域をしてしまうため、良くないということなんですね。


その相互参照を解決しているのが ModalViewのプロパティ宣言にある weak です。

weak var customDelegate: ModalViewDelegate?

weak弱参照 とも呼ばれ、
通常の定義(varやlet)とは対称的に強参照とも呼ばれます。

さきほど 参照されているかされていないか で判断すると言ったのですが、
具体的には、強参照があると 参照カウント(参照されている数)が増え、この参照カウントが1以上のときは、参照されているとみなされます。

そして、弱参照はこの 参照カウント を増やしません。

つまり、強参照がなく、弱参照のみになると、インスタンスは破棄され、メモリを空けてくれる、ということなんですね。

デリゲートは性質上、相互参照が常に起こってしまうので、
このように片方は 弱参照 を用いることが慣習となっています。

63
60
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
63
60