UITableView(以下简称TableView)是IOS应用中非常通用的组件,很多界面都可以使用TableView直接实现。但是我见过很多朋友实现TableView的DataSource和Delegate的时候,实现方法里面写了非常复杂,特别是cellForRowAtIndexPath方法,把很多Cel相关的代码也写到DataSource实现方法里面,特别是多种Cell风格的时候 ,那代码更是不敢恭维。一旦想要增加一种Cell类型,又要更改那个方法。代码维护性,可读性和健壮性都产生了很多负面影响。本文中,将为你展示一个tableView相关代码的整洁和组织技术。
1、本文整体思路
Cell完全由Model控制,cellForRowAtIndexPath方法只是做获取Cell和通知Cell刷新
2、增加基本Model
考虑到获取Cell的时候需要通过一个String类型的Identifier,所以我们将该Identifier保存在具体的Model里面,这样不同风格的Cell通过控制Model的Identifier就可以实现。而一般情况下一种Cell类型就对应一个Identifier;又考虑到每一种Cell对应一个Class类名也是唯一的。所以我们就将Cell的类名作为其Identifier。一般情况下Model具体实例一旦决定,对应的Cell也就决定了,所以我们就设计出了一个基本Model,代码如下:
/** 基本Model类 */
class BaseModel: NSObject {
/** 该Model对象对应的Cell的Identifier */
let cellIdentifier: String
/** 通过Cell类名初始化(关联Cell) */
init(cellClass: AnyClass){
self.cellIdentifier = NSStringFromClass(cellClass)
}
}
3、增加基本Cell
考虑到可以为Cell进行统一控制,比如点击效果啥的,我们也为Cell创建一个基本类,但是现在没有任何实现,代码如下:
/** 基本Cell类 */
class BaseCell: UITableViewCell {
}
4、为UITableView添加新的注册Cell方法
因为统一了Cell的Identifier,所以我们为UITableView添加新的注册Cell的方法(通过Cell类类型注册Cell),代码如下:
extension UITableView {
/** 注册通过xib创建的Cell */
func ex_registerNib(nibName:String, cellClass:AnyClass){
let cellNib = UINib(nibName: nibName,bundle: nil)
self.registerNib(cellNib, forCellReuseIdentifier: NSStringFromClass(cellClass))
}
/** 通过类名注册Cell */
func ex_registerCell(cellClass:AnyClass){
self.registerClass(cellClass, forCellReuseIdentifier: NSStringFromClass(cellClass))
}
}
5、事例
接下去我就用一个事例展示如何使用这些封装:
5.1、事例Model
class Model: BaseModel {
var number: Int
/** Cell点击回调,通过这种方式将Cell中的一些事件,比如按钮点击等回调到对应位置 */
var callback: ((model: Model) -> Void)?
init(cellClass: AnyClass, number: Int) {
self.number = number
super.init(cellClass: cellClass)
}
/** cell中文本的显示控制 */
var text: String {
return String(format: "我的Number是:%d", number)
}
/** cell高度控制(如果自适应高度则不需要此项) */
var height: CGFloat {
return 48
}
}
5.2、事例Cell
class Cell: BaseCell {
private var titleLabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// 初始化Cell控件
self.contentView.addSubview(titleLabel)
titleLabel.frame = CGRectMake(20, 10, 200, 30)
titleLabel.textColor = UIColor.redColor()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/** cell刷新代码 */
func refreshCell(model: Model) {
titleLabel.text = model.text
}
}
5.3、事例ViewController,包含大多数情况下DataSource和Delegate实现
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private var tableView: UITableView = UITableView()
private var models: [Model] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.ex_registerCell(Cell.self)
tableView.dataSource = self
tableView.delegate = self
self.view.addSubview(tableView)
tableView.frame = UIScreen.mainScreen().bounds
// 添加测试数据
models += (0..<10).map{ index in
let model = Model.init(cellClass: Cell.self, number: index)
model.callback = { data in print("click \(data.text)") } // 指定这个Model对应Cell点击事件
return model
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return models.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return models[indexPath.row].height
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.001
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0.001
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let model = self.models[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier(model.cellIdentifier, forIndexPath: indexPath) as! Cell
cell.refreshCell(model) // 关联Model和Cell
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let data = self.models[indexPath.row]
data.callback?(model: data)
}
}
6、总结
本文介绍了一种整洁地组织UITableView代码的方法,通过Model控制Cell,实现了代码的高可维护性和扩展性。
2840

被折叠的 条评论
为什么被折叠?



