環境: Swift3
よく使うのでコピペ用にメモしておく。
ViewController
import UIKit class ViewController: UIViewController { var items: [String] = ["foo", "bar", "hoge"] @IBOutlet weak var tableView: UITableView? override func viewDidLoad() { super.viewDidLoad() } } extension ViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell cell.item = self.items[indexPath.row] return cell } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 60 } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) } } final class MyCell: UITableViewCell { var item: String? { didSet { self.nameLabel?.text = self.item } } override func awakeFromNib() { super.awakeFromNib() } @IBOutlet weak var nameLabel: UILabel? }
カスタムセルMyCell
を定義する。
Storyboard 上でカスタムセルを貼り付けて定義している場合は以下のような register メソッドは不要。
逆にregister メソッドで登録してしまうとカスタムセルが表示されなくなってしまうので注意。
カスタムセルをコードのみで定義、または別途 nib ファイルで定義した場合は viewDidLoad などで以下のように register メソッドで登録する。
self.tableView?.register(MyCell.self, forCellReuseIdentifier: "MyCell") self.tableView?.register(UINib(nibName: "MyCell", bundle: nil), forCellReuseIdentifier: "MyCell")
また、普通やらないと思うが、カスタムセルを使う場合に UITableViewCell にデフォルトで用意されているプロパティ(textLabel
など)を使うと表示がおかしくなるのでやらないこと。
Storyboard
UIViewController に UITableView と UITableViewCell を貼り付ける。
UITableView の datasource と delegate を UIViewController に接続する。
UITableViewCell のクラス名を設定、Identifier を設定。
UITableViewCell 上にラベルなどがあればそれも接続する。
Extension
Cell・HeaderFooterViewのregisterやdequeueのIdentifierは文字列で扱うが、大抵はクラス名をそのまま使用するので、文字列ではなく、クラスを使って扱えるようにExtensionを定義する。
定義
extension UITableView { // func dequeueReusableCell(withIdentifier identifier: String, for indexPath: IndexPath) -> UITableViewCell // の代わりに使用する func dequeueReusableCell<T: UITableViewCell>(withClass type: T.Type, for indexPath: IndexPath) -> T { return self.dequeueReusableCell(withIdentifier: String(describing: type), for: indexPath) as! T } // func dequeueReusableHeaderFooterView(withIdentifier identifier: String) -> UITableViewHeaderFooterView? // の代わりに使用する func dequeueReusableHeaderFooterView<T: UITableViewHeaderFooterView>(withClass type: T.Type) -> T { return self.dequeueReusableHeaderFooterView(withIdentifier: String(describing: type)) as! T } // func register(_ nib: UINib?, forCellReuseIdentifier identifier: String) // func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String) // の代わりに使用する func register(tableViewCellClass cellClass: AnyClass) { let className = String(describing: cellClass) if UINib.fileExists(nibName: className) { self.register(UINib.cachedNib(nibName: className), forCellReuseIdentifier: className) } else { self.register(cellClass, forCellReuseIdentifier: className) } } // func register(_ nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String) // func register(_ aClass: Swift.AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String) // の代わりに使用する func register(headerFooterViewClass aClass: AnyClass) { let className = String(describing: aClass) if UINib.fileExists(nibName: className) { self.register(UINib.cachedNib(nibName: className), forHeaderFooterViewReuseIdentifier: className) } else { self.register(aClass, forHeaderFooterViewReuseIdentifier: className) } } } extension UINib { static let nibCache = NSCache<NSString, UINib>() static func fileExists(nibName: String) -> Bool { return Bundle.main.path(forResource: nibName, ofType: "nib") != nil } static func cachedNib(nibName: String) -> UINib { if let nib = self.nibCache.object(forKey: nibName as NSString) { return nib } else { let nib = UINib(nibName: nibName, bundle: nil) self.nibCache.setObject(nib, forKey: nibName as NSString) return nib } } }
使用時
// Cellの登録 // tableView.register(MyCell.self, forCellReuseIdentifier: "MyCell") tableView.register(tableViewCellClass: MyCell.self) // Cellの取得 // let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell let cell = tableView.dequeueReusableCell(withClass: MyCell.self, for: indexPath) // HeaderFooterViewの登録(MyHeaderView.nibを使用) // let className = String(describing: MyHeaderView.self) // tableView.register(UINib(nibName: className, bundle: nil), forCellReuseIdentifier: className) tableView.register(headerFooterViewClass: MyHeaderView.self) // HeaderFooterViewの取得 // let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: "MyHeaderView") as! MyHeaderView let view = tableView.dequeueReusableHeaderFooterView(withClass: MyHeaderView.self)