Swiftのdelegate(デリゲート)についてのメモ
Swiftのデリゲートって難しいですよね。そのデリゲートについての情報を備忘録を兼ねてメモしました。
Swiftのdelegateがよく分からない!という人の参考になれば。
Swiftのデリゲートとは?
簡単に言うと別のクラスに処理を委譲したり通知を受ける仕組みです。
ちょっとよく分からないですね。
例をとって説明してみます。あ、まずその先にdelegateの翻訳を見てみます。
delegate: 代表、(権限などを)委任する、派遣する
こんな意味です。Swiftでいうdelegateでは権限を委任するという訳がしっくり来ると思います。
簡単なサンプルでデリゲートを理解する
例えば、テキストフィールドに入力した文字をラベルに反映させるというサンプルアプリを作ってみます。
ここでの処理の一連の流れを書くと
- テキストフィールドにテキストを入力
- キーボードのreturn(確定)ボタンを押すと
- ラベルに入力した文字が反映される
こういった流れになります。なぜ2番目を赤文字にしているかと言うと、今回紹介するデリゲートについて大事な部分だからです。
UITextFieldはイベントを受け付けるだけ
このサンプルアプリで登場するのは、
- ViewController
- UITextField
- UILael
この3人です。キーボードで入力した文字を受け付ける肝の部分はUITextFieldが一手に引き受けていそうな感じがしますが、実はUITextFieldクラスには処理の内容まで記述されていません。
では、どうするのか?
UITextFieldではイベントの入力受付だけを行い、実際の処理はViewControllerクラスに任せてしまいます。(委任)
では、ViewControllerが処理を実装するにはどのようにすればよいのでしょうか?
実はUITextFieldにはイベントに応じての処理が記載されたUITextFieldDelegateというデリゲートプロトコルが用意されています。簡単に言うと、returnを押したらxxをする、削除を押したらxxをするという処理が記述されているプロトコルです。
この機能をViewControllerでも使いたいので、以下のように記述し採用を宣言します。
import UIKit class ViewController: UIViewController, UITextFieldDelegate { // UITextFieldDelegateを追記 @IBOutlet var textField: UITextField! @IBOutlet var label: UILabel! override func viewDidLoad() { super.viewDidLoad()
これで、UITextFieldDelegateが使えるようになりました。
このように書くとXcode上のサジェスト機能でUITextFieldDelegateに書かれている処理が表示されるようになります。
今回、実現したいのは「returnキーを押したらラベルを変更する」でしたね。すでにreturnキーを押したらxxという処理がUITextFieldDelegateに用意されています。
Xcode上でtextfieldと入力するだけで、returnキーを押したらxxを実行するというメソッドがサジェストされます。
ちなみに、1番上のクラス宣言の箇所でUITextFieldDelegateの使用を宣言をしないとこのサジェストは表示されません。
import UIKit class ViewController: UIViewController, UITextFieldDelegate { // UITextFieldDelegateを追記
なぜなら、UITextFieldDelegateの使用を宣言していないから。宣言していないものを使うことはできませんよね?
あとは、このメソッド内にキーボードで入力された文字をラベルに反映させるコードを書けばOKです。
func textFieldShouldReturn(_ textField: UITextField) -> Bool { // returnが押されたキーボードを閉じる(ここでは無視してOKです) textField.resignFirstResponder() // テキストフィールドに入力された文字(textプロパティが保持)を定数textに代入 let text = textField.text // 定数textをラベルのtextプロパティ(ラベルに表示される文字)に代入 label.text = text return true }
と、この処理を書けばめでたしめでたしと言ったところですが、これだけではラベルに文字が反映されません。
delegateの宣言はしたが、実際にdelegate(代理)していない
ここまでViewControllerでtextFieldDelegateを利用できるようにしました。
しかし、まだViewControllerが代理人となることを記述していません。
そこで、
textField.delegate = self
この一文を記述します。これは自身(ViewControllerクラスのインスタンス)をtextFieldのdelegateプロパティに代入することで可能となります。
全体のコードを乗せると、以下のようになります。
import UIKit class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet var textField: UITextField! @IBOutlet var label: UILabel! override func viewDidLoad() { super.viewDidLoad() // 自身をtextFieldのdelegateプロパティに代入(テキストフィールドのデリゲート(代理人)になる) textField.delegate = self } func textFieldShouldReturn(_ textField: UITextField) -> Bool { // returnが押されたキーボードを閉じる(ここでは無視してOKです) textField.resignFirstResponder() // テキストフィールドに入力された文字(textプロパティが保持)を定数textに代入 let text = textField.text // 定数textをラベルのtextプロパティ(ラベルに表示される文字)に代入 label.text = text return true } }