これは今後何度も使いそうになるのでメモ。
今回やることは、UITableViewの各セルの内容を独自のUIにしつつ、そのデータをネットワーク経由で取得するというもの。 Swift, Xcode 6.1。
UITableView を設置
いつも通りStoryBoardからUITableViewとUITableViewCellをそれぞれ配置。
UITableView の Outlets である dataSource
と delegate
のそれぞれの向き先を対象のViewControllerへ。 さらに UITableView の Outlets も ViewController に登録する。
カスタム UITableViewCell の作成
File -> New で Cocoa Class を指定。 名前を「CustomViewCell」にする。継承元に UITableViewCell を指定。すると、swift ファイルと xib ファイルの2つができる。
xib ファイルには既に UITableViewCellが設置されているのでその中にカスタマイズしたセルの内容を配置していく。配置したそれぞれのUI Objectは、 Outlet で CustomViewCell に登録しておく。
StoryBoard 内でCustomViewCellを指定
StoryBoard の UITableViewCell の CustomClass に CustomViewCell
を指定する。また、identifier を myCell
とする。
ViewController でコーディング
いよいよコーディングに入る。以下が基本形だ。
import UIKit class BoardViewController : UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var mTableView: UITableView! var posts: [AnyObject] = [] override func viewDidLoad() { super.viewDidLoad() // custom view var nib = UINib(nibName: "CustomTableViewCell", bundle:nil) mTableView.registerNib(nib, forCellReuseIdentifier:"myCell") mTableView.estimatedRowHeight = 100.0 mTableView.rowHeight = UITableViewAutomaticDimension } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return posts.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cell = tableView.dequeueReusableCellWithIdentifier("myCell") as? CustomTableViewCell var post = posts[indexPath.row] as Post cell?.message.text = post.content return cell! } func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath,animated: true) } }
CustomViewCell に表示する内容はエンティティとして作成する。上記例だと Post
。この配列をViewController内でフィールドとして保持し、その配列と対象メソッドの indexPath
を元に表示すべきエンティティを取得し、Cellに反映するといった流れだ。CustomTableViewCell への反映は上記コードの内, cell?.message.text = post.content
にあたる。
UITableViewAutomaticDimension
を指定すると、高さがコンテンツに応じて動的に変化するようになる。
ネットワーク経由での取得
さてこれで実行しても中身が無いので、空のテーブルが表示されるだけだ。ネットワークを通じてJSONデータを取得しよう。
今回はHTTP通信のライブラリとして Alamofire を利用する。インストール方法等は別途参照。
以下のような感じになる。
import Alamofire class BoardViewController : UIViewController, UITableViewDataSource, UITableViewDelegate { override func viewDidLoad() { super.viewDidLoad() // .... fetchData() } func fetchData() { Alamofire.request(.GET, "http://sample.com/posts.json") .responseJSON { (_, _, JSON, _) in var posts = JSON?["posts"] if let postArray = posts as? Array<Dictionary<String, AnyObject>> { for post in postArray { let p = Post( content: post["content"] as String //... ) self.posts.append(p) } } // update self.mTableView.reloadData() } } }
取得してフィールドのposts
にデータが入り終わった後にself.mTableView.reloadData()
するのがポイント。これで非同期にテーブルが更新できる。