型を値として扱ってると, キャストしづらい...
/// 素直に `protocol 名前: class where Self: 継承元` とやると,
/// 「Redundant constraint 'Self' : 'AnyObject'」
/// とか言われるので, とりあえず回避してみた.
protocol AnyObjectProtocol: class {}
/// とあるビューコントローラに表示するセルは, このプロトコルに準拠する.
protocol MyTableViewCellProtocol: AnyObjectProtocol where Self: UITableViewCell {
/// .xib ファイルの名前.
static var XIB_NAME: String { get }
/// Re-use Identifier.
static var IDENTIFIER: String { get }
/// 各種類別の, セルの高さ.
static var HEIGHT: CGFloat { get }
/// セルにデータをセットする, 共通のメソッド.
func setMyTableViewData(_ data: String)
}
extension MyTableViewCellProtocol {
///
/// 型を値として扱っているけれど, キャストしたい.
///
/// こんな方法しか思い付かなかったが,
/// もう少しスマートな方法があるのだろうか ?
///
static func cast(from: UITableViewCell) -> Self? {
return from as? Self
}
}
/// Foo タイプのセル.
class MyTableViewFooCell: UITableViewCell, MyTableViewCellProtocol {
static var XIB_NAME: String = "MyTableViewFooCell"
static var IDENTIFIER: String = "MyTableViewFooCell"
static var HEIGHT: CGFloat = 30
func setMyTableViewData(_ data: String) {}
}
/// Bar タイプのセル.
class MyTableViewBarCell: UITableViewCell, MyTableViewCellProtocol {
static var XIB_NAME: String = "MyTableViewBarCell"
static var IDENTIFIER: String = "MyTableViewBarCell"
static var HEIGHT: CGFloat = 80
func setMyTableViewData(_ data: String) {}
}
/// Baz タイプのセル.
class MyTableViewBazCell: UITableViewCell, MyTableViewCellProtocol {
static var XIB_NAME: String = "MyTableViewBazCell"
static var IDENTIFIER: String = "MyTableViewBazCell"
static var HEIGHT: CGFloat = 50
func setMyTableViewData(_ data: String) {}
}
/// 多種のセルをごちゃ混ぜに持つテーブルビューを持つビューコントローラ.
class TestViewController: UIViewController
, UITableViewDelegate
, UITableViewDataSource
{
/// セルのデータ.
private struct CellData {
/// セルのクラス.
var cellClass: MyTableViewCellProtocol.Type
/// セルのデータ.
var data: String
}
/// 便宜上ここにベタ書きするが, 本来は外部データを元に生成.
private let cellData: [CellData] = [
CellData(cellClass: MyTableViewFooCell.self,
data: "Foo セルのデータ1."),
CellData(cellClass: MyTableViewBarCell.self,
data: "Bar セルのデータ1."),
CellData(cellClass: MyTableViewBarCell.self,
data: "Bar セルのデータ2."),
CellData(cellClass: MyTableViewFooCell.self,
data: "Foo セルのデータ2."),
CellData(cellClass: MyTableViewBazCell.self,
data: "Baz セルのデータ1."),
CellData(cellClass: MyTableViewBarCell.self,
data: "Bar セルのデータ3."),
CellData(cellClass: MyTableViewBarCell.self,
data: "Bar セルのデータ4."),
]
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let cell_classes: [MyTableViewCellProtocol.Type] = [
MyTableViewFooCell.self,
MyTableViewBarCell.self,
MyTableViewBazCell.self ]
for cell_class in cell_classes {
tableView.register(
UINib(nibName: cell_class.XIB_NAME,
bundle: nil),
forCellReuseIdentifier: cell_class.IDENTIFIER)
}
}
func tableView(_: UITableView, numberOfRowsInSection: Int) -> Int {
return cellData.count
}
func tableView(_: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat
{
return cellData[indexPath.row].cellClass.HEIGHT
}
func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell_data = cellData[indexPath.row]
let cell = tableView.dequeueReusableCell(
withIdentifier: cell_data.cellClass.IDENTIFIER,
for: indexPath)
if let my_cell = cell_data.cellClass.cast(from: cell) {
my_cell.setMyTableViewData(cell_data.data)
}
return cell
}
}