在使用 UITableView 中,一个合乎 Apple 规范的 Cell 注册/使用流程需要至少两部分代码。
1.注册 Cell
tableView.register(MyCellClass.self, forCellReuseIdentifier: "CellIdentifier")
- 在 delegate 中完成 cell 的获取
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier") as! MyCellClass
return cell
}
当项目中多处用到 UITableView 时,这样的松耦合的写法很容易犯错,在不慎把 reuseIdentifier 或 MyCellCalss 的类型写错时很难发现错误。为此,做一个如下的扩展也许很有意义:
// MARK: - 让单元格支持复用的协议。
public protocol UITableViewCellReusableSupport : class {
/// 复用标识。
static var reuseableIdentifier: String { get }
}
// MARK: - 提供 UITableViewCellReusableSupport 的默认实现。
public extension UITableViewCellReusableSupport where Self : UITableViewCell {
/// 复用标识。
static var reuseableIdentifier: String {
return String(describing: self)
}
}
// MARK: - 扩展 UITableView 的特性。
public extension UITableView {
/// 注册一个可复用的单元格。
///
/// - Parameter cellClass: 单元格类型。
func register<T : UITableViewCell >(_ cellClass: T.Type) where T : UITableViewCellReusableSupport {
self.register(cellClass, forCellReuseIdentifier: T.reuseableIdentifier)
}
/// 获取一个可复用的单元格。
///
/// - Parameters:
/// - cellClass: 单元格类型。
/// - indexPath: 单元格位置。
/// - Returns: 获取的单元格。
func dequeueReusableCell<T : UITableViewCell>(_ cellClass: T.Type, for indexPath: IndexPath) -> T? where T : UITableViewCellReusableSupport {
return self.dequeueReusableCell(withIdentifier: T.reuseableIdentifier, for: indexPath) as! T
}
/// 获取指定位置的单元格。
///
/// - Parameters:
/// - cellClass: 单元格类型。
/// - indexPath: 单元格位置。
/// - Returns: 获取的单元格。
func cellForRow<T : UITableViewCell>(_ cellClass: T.Type, at indexPath: IndexPath ) -> T? where T : UITableViewCellReusableSupport {
return self.cellForRow(at: indexPath) as? T
}
}
搞定后,以后的代码可以这样写:
// 1. 自定义 UITableViewCell 时支持 UITableViewCellReusableSupport 协议
class MyTableViewCell: UITableViewCell, UITableViewCellReusableSupport {
}
// 2. 在 UITableView 中用如下方式注册 Cell
tableView.register(MyTableViewCell.self)
// 3. 在 delegate 中更精准的获取 Cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 获取的 cell 是 MyTableViewCell 类型,而不是 UITableViewCell 类型。
let cell = tableView.dequeueReusableCell(MyTableViewCell.self, for: indexPath)
return cell
}
// 4. 在使用 IndexPath 获取 Cell 时这样写
if let cell = tableView.cellForRow(MyTableViewCell.self, at: newIndexPath) {
// 获取的 cell 是 MyTableViewCell 类型,而不是 UITableViewCell 类型。
}
最后,UICollectionView 也可以这样做。
网友评论