note-テーブル

iOSアプリを作ろう・テーブルビュー入門

今回は Xcode 10.2 の Master-Detail App テンプレート解説の二回目でテーブルビューについて解説します。
スプリットビューの解説は「iOSアプリを作ろう・スプリットビュー入門」をご覧ください。

毎月札幌でiOSアプリ作りをアシストするセミナーをやっています。1時間にわたるセミナーの全内容を、物理的に参加できない方のためにnote上で公開します。ぜひアプリ作りにチャレンジしてください。

おしらせ
iOSアプリを作ろうシリーズのセミナーは今後も月一回のペースで続けます。
詳細は connpass.com の 札幌Swift でご確認ください。そして機会があればぜひ参加してください。
アプリ作りプログラミング教育に関連する話題は 札幌Swift のfacebookページ で発信しています。

快技庵(かいぎあん)の高橋です。
1980年代後半からのMacのアプリを作ってきた現役開発者で現在は電子書籍などのiOSアプリを作っています。
note や Twitter のアイコンは、最初に作った電子書籍アプリ豊平文庫のアイコンにしています。

テーブルビューのおさらい

最初にテーブルビューのおさらいと補足からはじめます。
iOSアプリを作ろう・テーブルビューと画面切り替え」でも基本的な説明をしましたが、テーブルビューは iPhone の画面に最適化されていて、設定アプリの画面や連絡先アプリの画面で使われています。
iOS では一覧表示のためだけでなく、メニューのような使われ方もされる重要な UI部品です。

テーブルは上下にスクロールできる一つのカラムを持っていて複数の行を表示します。
情報は行単位ですが、セクションで複数の行をグループ化できます。グループはABC順や五十音順に並べた索引としての使い方が多いです。
セクションには区切りとしてヘッダーとフッターを持ち文字などを表示できます。
ヘッダには画面右端のインデックスからアクセスすることもできます。

テーブルビューはナビゲーションビューコントローラーと組み合わせて使われるのがほぼデフォルトの使い方になっています。2段以上の階層もわかりやすく扱え、いつでも上位に戻れます。
例えば、電子書籍では 作家名の五十音別リスト で作家を選び 作家別の作品リスト から目的の作品を選び ダウンロード画面 の部分で「テーブルビューとナビゲーションビューコントローラーの組み合わせ」を使っています。

UITableView クラス

UITableView クラスは UIScrollView クラスを継承しています。(UIScrollView クラスは UIView を継承しています。)

class UITableView : UIScrollView

UITableView クラスはプロパティもメソッドも多い高機能で複雑なクラスです。(継承している UIScrollView もプロパティもメソッドも多いクラスです)
表示にはデータソースのしくみを使います。操作などのカスタマイズにはデリゲートを使います。

reloadData() メソッド

UITableView クラスにはたくさんのメソッドやプロパティがあります。

その中で reloadData() メソッド はテーブルの表示されているセクションやセルヘッダーフッターなどすべての内容を再ロードする利用頻度の高いメソッドです。(Master-Detail App テンプレートでは使われていません)
行数は同じで表示内容が変わる場合などに画面表示を内部データに合わせるために呼ぶメソッドです。

func reloadData()

そのほか指定行をスクロールして表示するメソッドなどもあります。
ドキュメントを参照してください。

insertRows(at:with:) メソッド

insertRows(at:with:) メソッドはテーブルビューに行を追加するためのメソッドです。

func insertRows(at indexPaths: [IndexPath],
               with animation: UITableView.RowAnimation)

先頭引数 at は行を指定する IndexPath型の配列です。複数の行を一度に追加できますが、複数の行を一度に追加するにはデータ追加処理で1行追加とは違った注意が必要です(データは後で説明するデータソースに追加が必要です)。

最初の引数の型が [IndexPath] となっています。大文字のアイではじまるので IndexPath型の配列であることがわかります。

with で挿入時のアニメーションを指定します。

指定した行の前に挿入します。
最後に挿入する場合は行インデックスを行数と同じで指定します。

deleteRows(at:with:) メソッド

テーブルビューから指定行をアニメーション付きで削除するメソッドです。(データは後で説明するデータソースから削除処理が必要です)
二つの引数を持ちます。
最初の引数で削除するセクションと行を IndexPath型の配列で指定します。
二つ目の引数でアニメーションを指定します。アニメーションは UITableView.RowAnimation 型で定義されています。
メソッドの宣言は次のようになっています。

func deleteRows(at indexPaths: [IndexPath],
               with animation: UITableView.RowAnimation)

Master-Detail App テンプレートでは、このメソッドはデータソースの tableView(_:commit:forRowAt:) メソッドで使っています。

テーブルビューの構造

テーブルビューに表示するデータは、データ1件が1行に対応する構造です。
行のグループとしてセクションがあります。
セクションはひとつの場合もあります。
テーブルビューはいくつかのセクションと行全体をスクロールして表示します。
セクションと行IndexPath型で管理します。

セルについて

行表示を担当するクラスが UITableViewCell です。略してセルと呼ばれることもあります。
セルは UIView を継承している、テーブルビューの行表示専用のビューです。

class UITableViewCell : UIView

標準の表示スタイルを4種類持っています。
種類によりひとつまたは二つのラベルを持ち、左端にアクセサリービューを持ちチェックマークのアイコンなどを表示できます。
右側にアイコンやサムネイルなどの画像を表示させることもできます。
行の高さはオートレイアウトで表示する文字(ラベル)により可変にできます。

標準スタイルのどれかであれば、配置されたラベルに次のプロパティからアクセスできます。

var textLabel: UILabel? { get }

このプロパティが読み出し専用なのは標準スタイルの場合の自動で作成されるためです。Master-Detail App テンプレートでもこのプロパティを使っています。

データソース

データソースはセクション数と行数や各セルの内容を返すオブジェクトのことです。テーブルビューに表示する内容を供給するのでデータソースと呼ばれます。
protocol UITableViewDataSource のメソッドを使って実装します。
各メソッドについて詳しくは後半で説明します。
ビューコントローラーをデータソースとして指定する場合が多いです。別のオブジェクトをデータソースに指定することもできます。

テーブルビューデリゲート

テーブルビューデリゲートで選択やスワイプ操作に対応したり、テーブルビューの外見をカスタマイズしたりできます。
protocol UITableViewDelegate のメソッドを使って実装します。
Master-Detail App テンプレートでは使われていません。

IndexPath 型

IndexPath型はセクションと行のような入れ子のデータ構造に対応する型です。
様々なメソッドなどを持つ struct ですが、テーブルビューで使う場合には次の二つのプロパティとイニシャライザを頻繁に使います。

var row: Int { get set }
var section: Int { get set }

init(row: Int, section: Int)

row プロパティが行の、section プロパティがセクションのインデックスです。それぞれのインデックスはゼロからはじまります

配列(Array)の復習

テーブルビューは配列ととても相性が良く、表示用データの管理は配列でおこなうとシンプルでわかりやすいコードになります。

配列(Array)は同じ型の要素順にしまう入れ物です。
配列の初期値の指定は同じ型の要素をカンマで区切り[ と ] で囲みます。

例:
要素が数値の場合:  [ 1, 3, 5, 7, 11 ]
要素が文字列の場合:  [ "松", "竹", "梅" ]
なお [ ] とすると件数ゼロの配列となります。(型の決まった配列専用)

配列型の書式:正式には Array<Int> などと型名を < と > で囲み要素の型を明示します。
または [Int] の書き方も可能です。(この書き方が多く使われている)
配列のイニシャライザも型の直後に()です。
整数型の配列のイニシャライザは [Int]() と書くことができます(件数ゼロの整数型配列のインスタンスを返します)。

配列の使い方

ゼロから始まるインデックスで要素を指定します。
注意 配列の要素数以上のインデックスを指定すると実行時エラーになります。(アプリは強制終了となります)

var rankName = [ "松", "竹", "梅" ]
rankName[0]       // "松" を返す
rankName.count	  // 3を返す
rankName[3]       // 実行時のエラー

rankName[0] でインデックス0の内容を取り出せます。
rankName[0]  = "上" でインデックス0の内容を右辺の値で置き換えます。
count は配列の要素数を返す読み出し専用プロパティです。

var count: Int { get }

配列はインデックスに注意

rankName.count が3の場合は rankName[2] までは正常に要素を取り出せます。
rankName[3] には対応する要素がないので実行時のエラーが発生しアプリは強制終了します。(ホームに戻ります)

配列要素の挿入

insert(_:at:) メソッドを使います。
最初の引数に挿入する要素を渡します。配列の他の要素と同じ型でなければなりません。
at: で何番目の要素として挿入するかを指定します。
インデックスゼロで先頭に挿入します。(常に at で指定したインデックスの前に挿入します)
at: インデックスに要素数を指定すると末尾に挿入します。それより大きなインデックスでは実行時エラーが発生します。

rankName.insert( "特上", at: 0)   // 先頭に"特上"を追加

挿入すると要素数がひとつ増え、挿入インデックス以降のインデックスはひとつずれます。

配列要素の削除

remove(at:) メソッドを使います。
削除するインデックスだけが引数です。

rankName.remove(at:1)   // インデックス1の要素を削除

要素数以上のインデックスを指定すると実行時エラーが発生します。

削除により要素数が一つ減ります。また削除したインデックス以降のインデックスもひとつずれます
連続して削除する場合には注意が必要です。(連続して削除する場合はインデクスの大きなものから削除する)

Master-Detail App テンプレート

iOSアプリを作ろう・スプリットビュー入門」でスプリットビューや画面遷移について解説しました。
この note ではテーブルビューへの行の表示・追加・編集を中心に解説します。

Master-Detail App テンプレートはスプリットビューを使ったシンプルなアプリです。プライマリペインでテーブルビューを使っています。選択した行の内容をセカンダリペインに表示します。
プライマリペインには追加ボタンがあり行を追加します。編集ボタンもあり削除操作も可能です。

新規プロジェクトでMaster-Detail App テンプレートを選び保存してください。(プログラミング言語はSwiftを選んでください)

シミュレータの機種に iPhone XR を選び実行してください。
Addボタン(+アイコンのボタン)で日時データを先頭行に追加します。
連続して追加ボタンをタップすると同じ秒表示となる場合があります。各行の表示の違いが微妙ですが、日時の秒が違うはずです。
追加は幾つでも可能です。
編集ボタンで削除できます。行のスワイプ操作でも削除可能です。
ヘッダーはありません、セクションはひとつだけです。

この note ではテーブル関連だけを解説します。
テーブルビューに関連するソースコードは MasterViewController.swift です。
先にストーリーボードファイルで MasterViewController 関連の設定を確認しましょう。

Main.storyboard

Master-Detail App テンプレートの Main.storyboard で MasterViewController に対応するシーンのテーブルビューを、アトリビュートインスペクターで確認すると Content は Dynamic Prototypes であることが確認できます。

Dynamic Prototypes はデータソースのコードを利用してテーブルビューを表示します。行数も各行に表示する内容もデータソースで自在にできます。

テーブルビューのアウトレットを確認

Master シーンのテーブルビューのアウトレット接続先をコネクションインスペクターで確認すると、データソースもデリゲートどちらも Master すなわち MasterViewController に接続しています。
MasterViewController は UITableViewController クラスを継承していてデータソースとデリベートのプロトコルに準拠しているため接続できるのです。

ストーリーボードでのセルの設定

ストーリーボードのテーブルビューには1行だけセルがあります。
このセルは行を追加する際のテンプレートとして働きます。

そのセルを選択しアトリビュートインスペクターで確認すると Style は Basic になっています。Basic は標準スタイルのひとつでラベルをひとつだけ持ちます。
Image は指定なしで、Identifier に「Cell」の設定があります。
データソースはこの Identifier を使ってセルの設定を取得します。

ここから先は

7,709字 / 16画像 / 1ファイル
この記事のみ ¥ 500

今後も記事を増やすつもりです。 サポートしていただけると大変はげみになります。