【Swift】hogehoge.delegate = self は何をしているのか。
はじめに
プログラミング経験:Ruby3 ヶ月。Python3 ヶ月
Swift 始めて 9 日目の人間が書きます。至らない点があると思うのでぜひご指摘お願いします。
前回:【Swift】俺はデリゲートなんか使わない。
デリゲートがよくわかりません。
特に、
hogehoge.delegate = self
← コイツ
コイツを理解するために徹底的に調べてみました。
デリゲートについて
デリゲートの概念についてはわかりやすいサイトや記事があるのでそれを参考にしてみてください。
Swift 言語を学ぶ
プロトコルとデリゲートのとても簡単なサンプルについて
簡単にまとめると、
デリゲートは他のクラスに処理を委譲したり、通知したりする仕組み
です。
① 処理を依頼するクラス
② 処理を依頼するクラスと処理を依頼されるクラスを取り持つプロトコル
③ 処理を依頼されるクラス
の 3 つの動きを理解するとわかりやすいです。
とりあえず実装してみる
仕組みはわかったけど実装できないと意味がありません。
デリゲートを用いて実装してみます。
「TextField(inputText)に文字列を入力後、return を押したら Label(outputText)に入力された文字列が表示される」という実装内容です。
import UIKit
class ViewController: UIViewController, UITextFieldDelegate { // 追加記述①
@IBOutlet weak var inputText: UITextField!
@IBOutlet weak var outputText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// 追加記述②
inputText.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// 追加記述③
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
let text = textField.text
outputText.text = text
return true
}
}
どうやら 3 つの記述を追加することでデリゲートを用いた実装ができるってことがわかります。
それぞれ何をしているのかみていきます。
①ViewController クラスが UITextFieldDelegate プロトコルに準拠することを宣言する
クラスがプロトコルに準拠しているとは、クラスがプロトコル(クラスの挙動を決めた設計図)を参照しているといったイメージだと思います。
では、なぜクラスをプロトコルに準拠させるんでしょう。
UITextFieldDelegate プロトコルの定義を確認してみましょう。
・UITextFieldDelegate を選択して右クリック(二本指でタップ)
・Jump to Definition をクリック
(この操作でクラスやプロトコルの定義を確認できます。)
UITextDelegate プロトコルに textFieldShouldReturn メソッドが定義されています!
他にも様々なメソッドが定義されていることがわかります。
UITextFieldDelegate に定義されている textFieldShouldReturn を使うためにこの実装が必要だったんですね。
まとめると、この実装で
依頼するクラス(ViewController)にこのプロトコル(UITextFieldDelegate)を使いますよと教えてあげていたということになるかと思います。
②inputText の delegate の通知先を自分自身に設定する
私はこの
inputText.delegate = self
に最も苦戦しました。日本語訳してみると、
UITextField クラスのインスタンスである inputText の delegate プロパティに ViewController のインスタンスを渡している
です。これがどういったことを意味しているのか理解するのが難しかったです。
※ プロパティについての参考サイト:Swift 言語を学ぶ
一旦、
inputText.delegate = self
からは離れて
outputText.text = text
を考えてみましょう。(上記実装内容の textFieldShouldReturn メソッドの 4 行目です)
あれ?なんか形似てますね。。。
これは何をしてるのか初心者の私でも直感的にわかりました。
UILabel クラスのインスタンスの text プロパティに UITextField クラスのインスタンスの text プロパティを渡しています。
UILabel と UITextField の定義を確認してみましょう。
2 つとも1行目に text プロパティが定義されていることが確認できます!
outputText.text = text
outputText は UITextField クラスのインスタンスなので、これは、outputText の text プロパティに text を代入することを意味します。
なるほど、だからこう実装することで UITextField(inputText)に入力された文字列を UILabel(outputText)に渡せるんですね。
それでは、
inputText.delegate = self
に戻ってみましょう。
これは、UITextField クラスのインスタンスである inputText の delegate プロパティに ViewController のインスタンスを渡しているんでしたね。
ふむふむ、なんだかさっきより飲み込めてきた気がします。
inputText は UITextField クラスのインスタンスです。
UITextField クラス確認してみます。
text プロパティと同じように delegate というプロパティが定義されているのが確認できます。
通常、変数の定義の時は型宣言をします。
open var text: String?
text プロパティであれば String 型が宣言されています。
これは、String 型の値を代入できる変数 text を定義しています。
※ 変数の型についての参考サイト:「分かりそう」で「分からない」でも「分かった」気になれる IT 用語辞典
weak open var delegate: UITextFieldDelegate?
同じように、delegate プロパティは UITextFieldDelegate を型宣言しています。
UITextFieldDelegate とはプロトコルです。
プロトコルを型宣言すると、変数にはそのプロトコルに準拠している値(オブジェクト)を格納できるようになります。
つまりこれは、UITextFieldDelegate プロトコルに準拠しているオブジェクトを代入できる変数 delegate を定義しています。
※ プロトコルの型宣言についての参考サイト:Swift プログラミング
※ オブジェクトについての参考サイト:クラスとオブジェクトとインスタンスの関係
inputText.delegate = self
inputText は UITextField クラスのインスタンスなので、これはinputText の delegate プロパティに self を代入しているという意味になります。
self は ViewController クラスのインスタンスですが、ViewController クラスは ① で UITextFieldDelegate プロトコルに準拠する宣言をしています。
すなわち、そのインスタンスである self もまた UITextFieldDelegate に準拠しています。
つまり、何を意味するかというと、
inputText が return を押されたら ViewController(私)に教えてね!
といったことかと思います。
return が押されたらという処理は ③ で実装するので、
② 単体の意味は、
inputText で UITextFieldDelegate プロトコルで定義されているメソッドが実行されたら ViewController(私)に教えてね!
ということになります。
inputText の delegate の通知先を自分自身に設定する
という表現をサイトでよく見かけましたが、ここまで細かく噛み砕いてようやく理解できました。
③delegate から通知してほしい内容を指定する
ここまで理解できてしまえば、③ の実装は問題ないかと思います。
依頼したい処理のメソッドとその後の処理を実装します。
delegate から通知してほしいのはreturn が押されたらというタイミングなので、その処理をしてくれるメソッドである textFieldShouldReturn を指定します。
#まとめ ##一般的な説明
①クラスがプロトコルに準拠することを宣言する
②delegate の通知先を自分自身に設定する
③delegate から通知してほしい内容を指定する ##自分なりの解釈
依頼するクラス:ViewController
依頼されるクラス:UITextField
プロトコル:UITexgFieldDelegate
①処理を依頼するクラスにこのプロトコルを使いますよと教えてあげる
②依頼されるクラスのインスタンスでプロトコルで定義されているメソッドが実行されたら私(ViewController)に教えてね!
③プロトコルで定義されているメソッドのうちなんのメソッドの処理を依頼するか指定する
①、②、③ の情報を整理された図がこちらのサイトでわかりやすくまとめられています。
文字ばかりで説明してしまったので思考の整理ができると思います。ぜひ見てみてください。
猿がもがきまくって理解した Swift のデリゲート(Delegate)という仕組み
こちらの記事もわかりやすかったです。
最終的には一般的な説明で理解しています。
一般的な説明の補助になれば幸いです。
Discussion