先上代码
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 下面的代码不能正确的执行。
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIDForCodeCustomCell", for: indexPath) as! CodeCustomCell
// Configure the cell...
cell.configure(modelData: (modelData?[indexPath.row])!) // fatal error: unexpectedly found nil while unwrapping an Optional value
return cell
}
两个错误:
1. fatal error: unexpectedly found nil while unwrapping an Optional value(一开始的错误注册后解决)
2. 即使注册了cell之后,View还是不能正确显示我自己自定义的cell
上面的代码不能正常工作。知道的是:
- dequeueReusableCell是为了系统为了提高效率的一个方法。具体就是在缓冲池里面看下有没有这个Cell。没有的话再初始化它这样。
- 后面的代码运行没有问题。
- 然后看了几篇相关的文章。貌似意思是说dequeueReusableCell除了在缓冲池里面找东西还做了点别的?
- Swift中的构造器解释init和自定义cell的问题
- 《重写prepareForReuse来重用UITableViewCell》-Cell重用的问题
引用下第一篇文章的话:
- 指定构造器必须调用它直接父类的指定构造器方法.
- 便利构造器必须调用同一个类中定义的其它初始化方法.
- 便利构造器在最后必须调用一个指定构造器.
引用下《重写prepareForReuse来重用UITableViewCell》的话:
重用cell的机制是利用缓冲池,将可重用的cell保存起来,显示cell时,先从缓冲池中取,如果缓冲池中没有此类的cell,也就是没有可重用的cell,此时就会重新初始化一份cell,并且加到缓冲池中。
最终问题得以解决,涉及这几个问题:
- 一个是Swift的几个init构造器的关系的问题上面的第4个就是对应的解析
- 另一个就是官方文档中强调的要注册的问题。
贴上修改后的代码。
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(CodeCustomCell.self, forCellReuseIdentifier: "CellIDForCodeCustomCell")
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIDForCodeCustomCell", for: indexPath) as UITableViewCell
// Configure the cell...
(cell as! CodeCustomCell).configure(modelData: (modelData![indexPath.row])!)
return cell
}
class CodeCustomCell: UITableViewCell{
var _imageView:UIImageView!
var label1:UILabel!
var label2:UILabel!
var label3:UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
_imageView = UIImageView(frame: CGRect(x: 50, y: 0, width: 88, height: 88))
label1 = UILabel(frame: CGRect(x: 0, y: 0, width: 42, height: 21))
label2 = UILabel(frame: CGRect(x: 0, y: 29, width: 42, height: 21))
label3 = UILabel(frame: CGRect(x: 0, y: 58, width: 42, height: 21))
}
func configure(modelData:ModelData){
label1.text = modelData.attr1
label2.text = modelData.attr2
label3.text = modelData.attr3
_imageView.image = UIImage(named: modelData.imageName)
self.addSubview(label1)
self.addSubview(label2)
self.addSubview(label3)
self.addSubview(_imageView)
}
required init?(coder aDecoder: NSCoder) {
// super.init(style: .default, reuseIdentifier: "CellIDForCodeCustomCell")
fatalError("init(coder:) has not been implemented")
}
}
顺带说说其他没能正常显示的原因:
- dataSource,delegate没有设置
- storyBoard没有和当前TableViewController关联
- storyBoard的cell的关联可以写也可以不写的
- 没有addSubView
最后附上自己分别用Storyboard文件,xib文件,代码直接定制3种方法定制自定义Cell的Demo链接
ThreeWaysToCustomYourCell