はじめに
swiftを学び始めた人が一番最初につまづくのがtableViewである、と僕は思っています。
その難しい要因を生み出しているものの一つがこれ。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
そう。こいつら。
実はこれらについて理解するには、delegateという概念を知っていなければなりません。
delegateとは何か
delegate、和訳すれば「委任する」とかなる言葉ですが、ではプログラムを委任するとはなんなのか。
さきほどのtableViewのコードを参考に考えてみましょう。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
このコードではtableViewのセルの数が1つになりますね。
重要なのは、このコードがViewControllerのコードの中に書かれていること。よくよく考えてみれば、tableViewに対して直接設定をしなくても設定がうまくいっていますよね。
これこそ、tableViewの設定コードをViewControllerに委任しているということなわけです。
ここで、ViewControllerに処理を委任するよ、ということを、ViewControllerに知らせなくてはなりませんね。
tableView.dataSource = self
これを書き忘れたことでコードがあっているのにtableViewに何も表示されないという経験をしたことがある人、結構いると思います。
ちなみに、tableViewにはdelegateというプロパティもありますよね。名前通りで、これもdelegateです。
実際にdelegateを作ってみよう
ここまでの説明でなーんとなくdelegateという存在が何者なのかわかったと思います。
そこで、実際に作ってみてより理解を深めてみましょう!
今回は、ボタンを押したら表示されている数が1増えるという基本的なアプリを、delegateを用いて作ってみようと思います。
delegateを用いない場合
さきにどんなものを作るのかのイメージです。
class ViewController: UIViewController {
@IBOutlet var label: UILabel!
var num: Int = 0
override func viewDidLoad() {
}
@IBAction func buttonPressed() {
num += 1
label.text = String(num)
}
}
どこにdelegateを用いるか
さて、その上でどんなふうにdelegateを用いるかですが、先ほど出したtableViewのように、画面のパーツをdelegateを用いて実装してみたいと思います。
今回は数字を表示するlabelをdelegateを用いて実装してみましょう!
delegateを用いた実装
まず、delegateを用いるので、わかりやすく区別するために新しいlabel(CustomLabel)を作ってみましょう。
class CustomLabel: UILabel {
}
そして、次に書くprotocolというものがdelegateの大本命となります。
protocol CustomLabelDelegate {
}
これでdelegateの外枠が作れました。
次に、CustomLabelとDelegateを接続します。
class CustomLabel: UILabel {
var delegate: CustomLabelDelegate? = nil
func reloadData() {
if let delegate {
self.text = delegate.labelText()
}
}
}
protocol CustomLabelDelegate {
func labelText() -> String
}
これで、CustomLabelがdelegateプロパティを持ちましたね。
このdelegateが設定されている、つまりnilでないなら、reloadData()
が呼び出された際に処理が行われる、という感じになっています。
加えて、protocolにfunc setText() -> String
とありますね。中身のない関数のような書き方がされていますが、これによって「こんな関数がありますよ、でもその内容は誰かに委託しますよ」ということが宣言できていることになっています。
さて、これらを用いて、ViewControllerのコードを書きましょう。
class ViewController: UIViewController, CustomLabelDelegate {
@IBOutlet var label: CustomLabel!
var num: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
label.delegate = self
}
@IBAction func buttonPressed() {
num += 1
label.reloadData()
}
func labelText() -> String {
return String(num)
}
}
こんな感じになります。
まとめ
流れをおさらいしましょう。
1. protocolでdelegateを作成
2. classにdelegateを持たせる
3. viewControllerにdelegateの先を設定し、viewController内でprotocolの関数を定義
4. viewController内からclassのdelegateに関連のあるメソッドを呼び出す
あまり自分から進んで用いることは多いようには思いませんが、使えるくらいに理解しておくことでTableViewへの理解がぐっと上がります!この記事が参考になると嬉しいです。
おまけ
delegateのところでこんな書き方をしていました。
if let delegate {
...
}
これは以下と同じ意味合いです。
if let delegate = delegate {
...
}
この書き方好き。