Swift言語で始めるiOSアプリ – UIViewControllerからUITableViewDataSourceの分離

ご無沙汰しております。松山事務所の石丸です。
業務が多忙なのを言い訳に、前回から3ヶ月も空いてしまいました。
前回までiOS入門という内容で記事を書いてきましたが、今回からはもっと実用的(?)なコードや、アプリの作りについて書いていきたいと思います。

今回の内容はタイトル通り、UIViewControllerからUITableViewDataSourceの分離についてです。

開発環境はOS X EI Capitan(ver10.11.6)、Xcode(ver7.3.1)で、Swiftのバージョンは2.2になります。

 

icon-check よくある実装

UITableViewを使ったサンプルプログラムのほとんどが、UIViewControllerでUITableViewDataSourceプロトコルを実装しています。
わかりやすさのため最小限のコードでUITableViewの使い方を表現するには適切なサンプルです。

ここでは面倒なことに画面内に2つのUITableViewがある場合のコードを書いてみました。

UIViewControllerはUITableViewDataSourceプロトコルを実装し、それぞれのUITableViewにStoryboard上で設定したtagによって処理を振り分けています。
本来なら各UITableViewに設定するtagはコード上で定数を定義したいところですが、InterfaceBuilderから参照できないので、tagを表すenumを定義しています。

実行結果は次のようになります。

 

 

icon-check なぜUITableViewDataSourceを分離するのか

業務や趣味でちゃんとアプリを作り始めると、TableViewに関するコードでUIViewControllerがどんどん太ってしまい見通しが悪くなります。

また、各UITableViewがdataSourceとしてUIViewControllerに依存しているため、他の画面で再利用もできません。
tagで分岐するためのswich文もUIViewController内に散らばってしまいます。
画面と分離しやすいUITableViewDataSourceをUIViewControllerから分離することで、UIViewControllerをスマートに保つことができます。

 

icon-check シンプルなデータ構造のUITableViewDataSource

UITableViewDataSourceプロトコルの実装必須なメソッドは、
セルを作って返すメソッド
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

テーブルの行数を返すメソッド
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
の2つです。
サンプルもそうであるように、シンプルなデータ構造であれば、データを配列で保持し、indexPath.rowで対応するデータからセルを作り、テーブルの行数は配列のcountが対応します。

保持するデータ型はGenericsで指定し、イニシャライザでセルのIDとセルにデータを設定するコールバック関数を受け取ります。
データに応じてセルのIDが変わるような場合は、セルの生成をまるごとコールバック関数にまかせてしまう作りもありますが、ここでのキモはNSObjectを継承しているところです。
NSObjectを継承しなかった場合は、
Type ‘TableViewDataSource<T>’ does not conform to protocol ‘UITableViewDataSource’
というエラーが出ます。

参考サイト:How to make a class conform to a protocol in Swift?

 

icon-check ViewControllerの実装

TableViewDataSourceを使ったUIViewControllerの実装は次のようになります。

いかがでしょう?
各UITableViewのdataSourceとしてUIViewControllerではなく、TableViewDataSourceを指定し、データの管理はTableViewDataSourceに任せてしまいます。tagで分岐するためのswich文もなくなり、だいぶスリムになったのではないでしょうか。

今回はここまで。ありがとうございました。

 

̃Gg[͂ĂȃubN}[Nɒlj