分割した片側にテーブルビューを表示してみる
今回は、左側に表示されるビューコントローラーにテーブルビューを表示し、その中から選んだ項目の内容が、右側のビューコントローラーに表示されるという、よくあるパターンのアプリを作ってみます。その場合、一般的なアプリでは、スプリットビューコントローラーとナビゲーションコントローラーを組み合わせるのが普通です。それにより、iPhoneなどで分割表示できない場合には、普通のナビゲーション機能によって表示をそっくり入れ替えるような動作が可能になります。この例では、プレイグラウンドのポートレート画面と言えども、常に2分割表示することに決めているので、ナビゲーションコントローラーは使いません。
とりあえず、左側のビューコントローラーをUIViewControllerからUITableViewControllerのオブジェクトに変更し、2つのビューの背景色も変更してみます。
これだけでも、急に意味のあるアプリっぽい画面に見えてくるから不思議です。もちろん、これだけでは単にそんな気がするだけで、実際はまだ意味のある機能を発揮できません。テーブルビューに何かを表示するには、テーブルビューコントローラーのサブクラスを定義して、その中身をプログラムすることが必要です。ここでは、アップルの製品サイトのトップにある、5つの製品カテゴリーの名前をテーブルの項目として表示することにします。そのための最小限のメソッドとして、numberOfRowsInSectionとcellForRowAtを実装します。
ついでに2番目のビューコントローラーとしてプログラムする独自クラス、DetailViewControllerも作っておくことにしました。親クラスは素のUIViewControllerで、中身はまだ空です。
プログラムの後半部分、スプリットビューコントローラーを導入しているあたりは、上の例とほとんど同じです。実行結果とともに確認してください。
プロトコルを使って2つのビューコントローラー間のデータ受け渡しを実現する
もうだいたい見通しが立ったと思いますが、左側のテーブルビューから選んだ製品カテゴリーの内容を、右側のビューに表示しようと考えています。その内容としては、ウェブビューを使って、アップルの製品サイトをそのまま表示することにします。
テーブルビューで選んだ情報を別のビューコントローラーに伝えたいわけですが、以前にも取り上げたようにナビゲーションコントローラーを使う場合は簡単です。その際は、切り替え先のビューコントローラーのオブジェクトを切り替え元で作ることになるため、切り替え先のオブジェクトのプロパティに直接情報を書き込むことができるからです。しかし今回は、互いに独立した、ほぼ対等のオブジェクト間で情報をやり取りするので、そのパターンは使えません。
それを実現するために、これまでと比べるとちょっと高度なiOSプログラミングのテクニックを使います。とはいえ、実は今までにもそのテクニック自体は何度も登場しているのです。ただこれまでは、フレームワークのクラスが用意している仕組みを利用するだけで、自分でその仕組みを作ることはしませんでした。今回は、初めて、その仕組みを自ら作って自ら使うことになります。
その仕組みとは、SwiftがObjective-Cから受け継いだ「プロトコル」です。そのプロトコルを利用して「デリゲート」というオブジェクトを作ります。デリゲートは、いわゆる「権限移譲」のことで、ある処理を自分に変わって他人にやってもらうための仕組みです。このあたり詳しく説明していくとかなり長くなるので、今回は実際のコードを見て何となくわかったような気になっていただければ十分でしょう。
まず、そのプロトコルを定義します。名前は自由に付けられますが、これはデリゲートであることを示すために、ProductSelectionDelegateというクラスとして、1つのメソッドproductSelectedを宣言しておきます。
このメソッドの中身は、ここには書きません。それは、このプロトコルに準拠するクラスの仕事です。そして、ほかのクラスがそのメソッドproductSelectedを呼び出すことで情報が伝達されます。具体的には、メソッドを呼び出す側(この場合は左側のテーブルビューコントローラー)が、sProductという引数(この場合はString型)にセットした値によって、選択された製品カテゴリーの名前がデリゲートとなったオブジェクト(右側のビューコントローラー)に伝えられます。
テーブルビューを表示するためのProductsViewControllerクラスは、自分のデリゲートになってくれるオブジェクトを記録しておくために、その名もdelegateというプロパティを用意します。そのタイプは、上で定義したプロトコル、ProductSelectionDelegateのクラスです。
また、このクラスには、テーブルビューの項目が選択されると呼び出される、didSelectRowAtメソッドも実装しておきます。そのメソッドの中で、デリゲートのproductSelectedメソッドを呼び出し、選択された項目の名前の文字列を渡します。
もう1つのDetailViewControllerクラスは、最初に定義したProductSelectionDelegateプロトコルに準拠させます。
それにともなって、productSelectedメソッドを実装しますが、まずは単純なものにしておきました。ビューの真ん中に配置したラベルのテキストに、引数として渡された文字列をセットして、製品名を表示するだけです。
例によって、それ以外の部分は実行結果とともに確認してください。
最初はテーブルビューで何も選択されていないので、「未選択」と表示されています。この図のコードでもっとも重要なのは、vc1のデリゲートとしてvc2を設定している、
vc1.delegate = vc2
という部分です。これによって、vc2がvc1のデリゲートとなり、vc1からvc2のメソッド(productSelected)を呼び出せるようになるのです。
テーブルビューから何か選択すると、その名前がデリゲート側のメソッドを呼び出すことで伝達され、右側のビューに表示されます。
アップル製品の電子カタログアプリに仕立ててみる
ここまでできれば、あとはどのような用途にも活用できます。この例では、右側のビューコントローラーのビューをウェブビューにして、受け渡された製品名のサイトを開きます。ウェブビューについては以前に取り上げたので、今回は説明を省きます。ここでは、productSelectedメソッドの中で、渡された製品名をすべて小文字にして、アップルの製品ホームのURLの後ろに付けることで、製品サイトのURLを作っています。あとはそのURLをリクエストに変換して、ウェブビューにロードするだけです。
このプログラムを実行すると、最初はアップル製品のホームが表示されます。
ここから、テーブルビューで製品カテゴリーを選べばそのページが開きます。
今回の例は、縦長のプレイグラウンドのビューにとっては、あまり実用的ではなかったかもしれません。それでも、スプリットビューコントローラーの基本的な機能と、最小限の使い方は、十分に理解していただけたことと思います。
次回の予定
今回は、主にSwift Playgroundsでもスプリットビューコントローラーが使えることを確かめる目的で、簡単な応用例をプログラムしてみました。あとはそれを使って何をするか、という問題なので、とりあえずこの話題はここまでとします。次回には、複数のビューコントローラーの内容を同時に表示するための、また別の機能を取り上げます。これまでのような特殊なビューコントローラーによるのとは、ちょっと違った方法です。そこまで自在に扱えるようにしておけば、どんなタイプのアプリにも応用できるでしょう。