感じていた疑問
いくらかネットや書籍を見てみたが、いまいちわからなかったこととして、
- たとえば
inputText.delegate = self
としてDelegate先をしているとあるが、selfって結局どれ?inputText.delegate
なのかinputText
なのかViewControllerクラスかでもクラス名を右辺にもってくるってどういう了見? - 巷のシンプルなDelegate例だと、Protocolに
func
は定義されているが中身がなさすぎて「中身がないメソッドを定義する意味がわからん、メソッド名を固定しているくらいやん」となった
実際のところ、自分が腹落ちするように曲解している可能性もあるが、少なくとも上記疑問点は解消した。
サンプルを使った自分なりの解釈
シンプルでわかりやすいので、「TextFieldに文字列を入力してReturn(Enter)を押したらキーボードを閉じるプログラム」をUIKitで実装した場合を考える。一応念の為助言しておくと、以下はSwiftUIで実装していないので、もしSwiftUIしか勉強していなければ回れ右したほうが良い。
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
inputText.delegate = self
}
@IBOutlet weak var inputText: UITextField!
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
ひとまず最初はDelegateの意味を「アプリで操作された内容とタイミングを通知してくれて、私たちが行いたい処理を実装できる仕組み」(「たった2日でマスターできるiPhoneアプリ開発集中講座 Xcode 11 Swift 5対応」、ソシム、2019)だとする。その上で、なんだか設計に有利な考え方が使われているらしいと思っておく。
Delegateを考える際は、以下の登場人物を念頭に置く。
- Delegate元(処理を依頼する側 ;依頼人)
- Delegate先(処理を代理する側;代理人)
- Delegate Protocol(上の2人が処理を依頼・代理する際の約束事;これを守っている(conform: 批准する、準拠する、従う)者のみ代理人になれる)
上記実装例の場合、
- Delegate元→UITextFieldクラス
- Delegate先→ViewControllerクラス
- Delegate Protocol→UITextFieldDelegate
代理人をどうやって定義しているかというと、inputText.delegate = self
である。1つずつ見ていくと、
inputText
はUITextField(つまり依頼人)型(注1)の変数であり、UITextFieldの定義を参照するとvar delegate: UITextFieldDelegate!
であることから.delegate =
でDelegate先が指定できるself
の定義を参照するとlet `self`: ViewController
である(注2)ことから、ここでいうself=自身とは「ViewController(型(注1)の変数)」- したがって、ViewControllerクラス内のメソッドとして処理の中身を実装する(これをDelegate Methodという)
textFieldShouldReturn()
がDelegate Methodである。ここで「中身を実装する」と強調したのは、今回の場合textFieldShouldReturn()
が「Returnキーを押した後に入力情報を引数として与えられて〇〇が実行される」ことは事前にProtocolで約束されており、実装することは〇〇に限定されるからである。つまり〇〇はDelegate先の実装内容に依存する。
逆に言えば、〇〇以外の約束事はDelegate先を一切気にせず設計できる。この考え方がつまりデザインパターンであり、簡単に言えば使い回せる(repeatable)設計になっているということである。なお、今回はすでに実装された設計を利用していることに注意したい。また、利用する側であるこちらも約束事がどのように実装されているかは気にせずともよく、実際どのようになっているかは知らないまま上記プログラムを実装できている。
注釈
(注1)var inputText: UITextField
と実装されている場合、UITextFieldクラス「型」の変数っていうのか?: String
だったらString型とか文字列型と言えるだろうが、一般的な言い回しがわからない
(注2)ここでself
をbacktick(`)で挟んでいるのは、その単語が予約語だからである(classという名前の変数を定義したい場合は同様にvar `class`: Int
のように記述する)
参考資料
- 「たった2日でマスターできるiPhoneアプリ開発集中講座 Xcode 11 Swift 5対応」、ソシム、2019
- プロトコルとデリゲートのとても簡単なサンプルについて - Qiita