schoo で iOS の授業をしてきました [Table View を使って Web API で取得した情報を表示する編]

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

スクリーンショット 2015-10-26 15.58.55

前回に引き続き、9月にオンライン授業サイト schoo(スクー) 様にて授業させていただいた技術について、補足・解説をしていきます。

授業が録画されているものが授業サイト上にあります(リンクは後述)。より理解を深めたい方は、こちらをご覧頂ければと存じます。

謝辞

スクー様では、企画段階から事前の授業資料のフィードバック、そして放送の本番に至るまで、様々な方にお世話になりました。またクラスメソッド社内ではコードや授業資料のレビュー、さらにプレ授業を社内でやらせていただきフィードバック頂くなど、お世話になりました。ありがとうございました!

リンク

授業ページ

GitHub

ゴール

※ 以下、2回目の授業での授業の内容を補完する形で、書いていきたいと思います。

検索ワードを入力すると、曲情報が一覧形式で表示されるアプリを作ることが、シリーズを通してのゴールになります。

今回の完成品

iOSアプリ開発実践(2) 2015-09-01.043

今回の完成品はコレです。Web API で取得した曲データを、Table View を使って、綺麗に一覧表形式で表示する所までやってみます。

コードは、こちらになります。

SongsViewer/SongsTableViewController.swift at master · cm-ttamiya/SongsViewer · GitHub

Table View とは

iOSアプリ開発実践(2) 2015-09-01.007

  • iOS などで使用可能な、一覧形式で情報を表示する仕組み
  • 文字や画像を表示できる

Table View での情報表示の流れ

iOSアプリ開発実践(2) 2015-09-01.009

Table View の側から行の数やセルの中身について問い合わせがあります。 プログラムの側ではそれに応える形で、各種情報を受け渡します。

Table View 上に 1〜100 までの数字を表示

iOSアプリ開発実践(2) 2015-09-01.010

プログラムファイルを追加

  • NumberTableViewController.swift の名前で、UITableViewController のサブクラスとして新規ファイルを作成しましょう。

Storyboard 上での操作

  • Table View Controller を追加
    • 適当な位置にドラッグ&ドロップします
    • initial view controller として設定します。この画面が起動後に最初に読み込まれるようになります。
    • Custom Class として、NumberTableViewController を指定しましょう。これがないと、プログラムの側で表示内容を指定しても、画面に反映されません。
  • Cell の reuse identifier を設定
    • 一覧形式で表示する項目について、識別子を設定します。これがないと、うまく表示することが出来ません。
    • reuseIdentifier を設定しましょう。後で、プログラムの中でも同様の文字を入力します。

NumberTableViewController.swift を改造

NumberTableViewController.swift の中身を見てみましょう。すでに、沢山の文字が入力された状態になっています。コレを改造することで、思った通りの一覧表を表示できるようになっています。実際に改造していきましょう。

numberOfSectionsInTableView (セクションの数)

numberOfSectionsInTableView の名前が付いている部分を探しましょう。

Table View にはセクション(表示上の区切り)を設定できます。今回は、表示上の区切りを指定しませんが、内容を表示するために、最低1個のセクションが必要です。今回は、1を指定します。

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

numberOfRowsInSection (行の数)

numberOfRowsInSection の名前が付いている部分を探しましょう。

表示したい行の数を指定します。今回は100個の表示欄が必要ですので、100を指定します。

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
}

cellForRowAtIndexPath (セルの中身)

iOSアプリ開発実践(2) 2015-09-01.023

cellForRowAtIndexPath の名前が付いている部分を探しましょう。

表示しようとしているセルの中にどんな情報を表示するかを指定します。

「表示しようとしているセル」とはどういうことでしょうか。一覧形式で表示する際、今回を含め、一度に画面に収まりきれない量が表示されることに備え、Table View はスクロール可能な一覧表となっています。例えば 1000 行の表を表示する場合、最初から 1000 行目までの中身を指定していては、処理が膨大になってしまい、画面表示がもたつくなどの問題が発生します。そこで Table View では、実際に画面に表示される時に、その中身をプログラムに問い合わせる仕組みになっているのです。

Storyboard で設定したセルの識別子 reuseIdentifier を指定しています。

cell.textLabel?.text = String(indexPath.row) で、各行に、その行が何行目かを表示するよう指定しています。

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as! UITableViewCell
        cell.textLabel?.text = String(indexPath.row)

        return cell
}

indexPath

ここで、indexPath.row という記述があります。これはなんでしょうか。

iOSアプリ開発実践(2) 2015-09-01.024

この図のように、セクションと何行目であるかを指定するためのものです。

  • indexPath.section には、表示しようとしているセルが何セクション目にあるか
  • indexPath.row には、表示しようとしているセルが何行目にあるか

が、それぞれ入ってきます。

曲情報を Table View で一覧表示

前回作成したプログラムを元に、Web API で取得した情報を Table View 上に表示してみます。

プログラムファイルを追加

  • SongsTableViewController.swift の名前で、UITableViewController のサブクラスとして新規ファイルを作成しましょう。

Storyboard 上での操作

先ほど同様、以下の部分について、Storyboard 上で指定していきます。

  • Table View Controller を追加
    • 適当な位置にドラッグ&ドロップします
    • initial view controller として設定します。この画面が起動後に最初に読み込まれるようになります。
    • Custom Class として、SongsTableViewController を指定しましょう。これがないと、プログラムの側で表示内容を指定しても、画面に反映されません。
  • Cell の reuse identifier を設定
    • 一覧形式で表示する項目について、識別子を設定します。これがないと、うまく表示することが出来ません。
    • reuseIdentifier を設定しましょう。後で、プログラムの中でも同様の文字を入力します。

SongsTableViewController.swift を改造

以下の流れで改造していきます。

  • 前回のコードを適切な場所にコピー&ペースト
  • 個別の曲情報を抽出したものを、セルの内容をとして返す
    • songs["trackName"]
  • section (=1), row (=曲数) の数を返す
    • 曲数と同じ行数が表示された一覧表を表示するため
  • Table View の表示更新

前回のコードの一部をコピー&ペースト

iOSアプリ開発実践(2) 2015-09-01.036

showSongs メソッドを前回のプログラムからコピーしてきて貼り付けます。

メソッド名変更

今回のプログラムでは、このメソッド内で表示処理はおこないませんので、fetchSongs に名前を変更しましょう。

private func showSongs()

を、以下に書き換えます。

private func fetchSongs()

プロパティ設定

var songs = [[String:AnyObject]]()

次に、プログラムの冒頭に近い部分に、この記述を追加します。曲情報を、プログラム内の様々な場所から読み書きするための、「プロパティ」という仕組みで書かれたものです。[String:AnyObject]型の曲情報がいくつも入る配列を指定・初期化しています。

曲情報をプロパティに受渡し

for song in results
{
let trackName = song["trackName"] as! String
println(trackName)
}

前回は、曲情報が得られた段階で、すぐに Xcode 上に表示を行っていました。

self.songs = results

しかし、今回は、Table View の仕組みの中でゲットした情報を扱います。一旦情報を保持しておきましょう。プロパティで作成した songs の中に、複数の曲の情報を受渡します。

numberOfSectionsInTableView (セクションの数)

今回もセクションによる表示の区切りを使いませんので、1を指定します。

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

numberOfRowsInSection (行の数)

Web API でゲットした曲数分の表示を行いますので、行の数は、以下になります。プロパティ songs の中に入っている要素の数 count を表しています。

self.songs.count

これを使って、numberOfRowsInSection の中身を指定しましょう。

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.songs.count
}

cellForRowAtIndexPath (セルの中身)

前回は、すべての曲情報を一気に表示していました。今回は、cellForRowAtIndexPath で各行のセルの中身を順次指定して行きます。

let song = songs[indexPath.row] //[String:AnyObject]型の値を取り出す

プロパティ songsindexPath.row 番目の情報を song に渡しています。今回、一覧表の行の数と、プロパティ songs に入っている曲の数は一致しています。このことを利用した処理です。

cell.textLabel?.text = song["trackName"] as? String
cell.detailTextLabel?.text = song["artistName"] as? String
return cell

後は、必要な情報をキー名を指定することで取得し、セルに設定しています。

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as! UITableViewCell
        let song = songs[indexPath.row] //[String:AnyObject]型の値を取り出す
        cell.textLabel?.text = song["trackName"] as? String
        cell.detailTextLabel?.text = song["artistName"] as? String
        return cell
    }

ここでの処理全体としては、このようになります。

Table View の表示更新

ココで説明するのは、とても一瞬の出来事についてです。

プログラムが起動した直後、画面には空の一覧表が表示されます。この時、データはまだ読み込まれていません。

その後、viewDidLoad から fetchSongs が呼び出され、プロパティ songs に曲情報が受け渡されます。しかし、一覧表には反映されません。相変わらず、データが空だったときの状態(行の数、セクション数、内容)を反映していますnumberOfRowsInSection(行数)の部分ではデータが空の状態では 0 なので、ひとつも内容が表示されない状態となってしまいます。

self.tableView.reloadData()

この処理によって、データが更新されます。

仕組みとしては、numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath といった名前の付くメソッドが再度呼ばれるようになっています。これにより、データの数を反映した行数、現在画面に表示される必要のあるセルの中身の更新が行われます。

実行

iOSアプリ開発実践(2) 2015-09-01.045

このように、一覧表形式で、データが表示されました!

次回

次回は、いよいよアプリ完成です。 検索欄を実現する Search Bar を追加します。自由な検索語句を使って、曲を検索できるようになります。また、セルに画像を表示し、見た目をゴージャスにします。