はじめに
プログラミング経験: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)という仕組み
こちらの記事もわかりやすかったです。
最終的には一般的な説明で理解しています。
一般的な説明の補助になれば幸いです。