Swiftで「TableViewのcellをタッチして詳細画面に移る」という画面遷移を考える。遷移前はTableView(またはTableViewを包むViewController)であり、遷移後は通常のViewControllerである。
前提
遷移前 ViewControllerのTableView
遷移後 ViewController
ストーリーボードでセグエを作っているとする。セグエは必ずTableViewのcellから引っ張る。identifierもきちんと設定しておく。セグエの始点と終点、identifierを正しく設定しないとエラーが出る。
結論:didSelectRowAtではなくprepareを使う
SwiftでtableViewからデータを受け渡すとき、didSelectRowAtはなるべく使わない。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {...}
代わりにprepareを使う。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if ( segue.identifier == "yourViewIdentifier" ) {
let x = self.YourTableView.indexPathForSelectedRow
let y = x?.row
let post = self.posts[y!]
let p : PostViewController = segue.destination as! PostViewController
p.param = post.thumbnail
}
}
イベントが2回発生するエラー
didSelectRowAtとprepareを両方とも用意していると、画面遷移のときにイベントが2回発生する。それ自体はエラーでない。画面遷移でデータを渡すときにエラーになる。
didSelectRowAtがあってもなくてもprepareは必要になる(ようだ)。prepareは必要だが、didSelectRowAtはあってもなくてもかまわない。そしてデータをきちんと渡すためには、prepareだけで十分である。
prepare内でindexPathForSelectedRowを使い、cellの順番を取得する
画面がリストから詳細に移るときを考える。このとき、イベントのあったcellが何番目のcellか、cellにどのような情報が含まれているかがわからないといけない。
多くのサンプルではdidSelectRowAtを使うが、結局はprepareを使ったほうが早い。そしてエラーがない。prepareでcellの情報を知るには、indexPathForSelectedRowというメソッドを使う。
indexPathForSelectedRowは、遷移前のviewのIBOutletで定義しているフィールドのメソッドである。
@IBOutlet weak var YourTableView: UITableView!