我有一个细胞类' NewsCell' (UITableViewCell的子类)我用于两种不同的新闻:OrganizationNews和ProjectNews。这些新闻有共同点,但有些元素不同。也就是说,当我的单元格用于ProjectNews时,我想隐藏组织的标识,当它用于OrganizationNews时,我想隐藏项目的名称按钮。
我有'configureCell(_,forNews,ofProject)'方法。我在' NewsViewController'中称呼它。我使用了' removeFromSuperview'方法,因为我需要在' NewsCell'中重新安排我的元素。改变'隐藏'价值不会给我带来这种效果。
所以,这就是问题所在。我有'线程1:致命错误:在解开一个Optional值时意外发现nil'行projectNameButton.removeFromSuperview()或logoImageView.removeFromSuperview()中的异常。 我该怎么办?
// NewsViewController.swift
func configureCell(_ cell: NewsCell, forNews news: News, ofProject project: Project? = nil) {
//...
if news is OrganizationNews {
cell.projectNameButton.removeFromSuperview()
} else if news is ProjectNews {
cell.logoImageView.removeFromSuperview()
}
// ...
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let news = newsCollection[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.newsCell, for: indexPath) as! NewsCell
configureCell(cell, forNews: news)
cell.delegate = self
return cell
}
答案 0 :(得分:0)
更改删除行,如下所示
if news is OrganizationNews {
cell.projectNameButton?.removeFromSuperview()
} else if news is ProjectNews {
cell.logoImageView?.removeFromSuperview()
}
这将解决问题。但一个好的方法是为每个单元格创建单独的类。您可以创建一个基类来保持公共逻辑。
答案 1 :(得分:0)
UITableView或UICollectionView构建于 重用 概念之上,当您处理单元格时,这些单元格将被重用并重新填充。
当您尝试调用dequeReusableCell(withIdentifier:)
时,它有时会返回之前创建的内容。所以,假设你在拥有所有控制权的东西之前进行了dequed,然后删除了一个(removeFromSuperview
),然后再次尝试deque,新的dequed可能没有子视图。
我认为最适合您的解决方案是制作两个不同的单元格。
<强> 实施例 强>
class BaseNewsCell: UITableViewCell {
// Put the common views here
}
class OrganizationNewsCell: BaseNewsCell {
// Put here things that are ONLY for OrganizationNewsCell
}
class ProjectNewsCell: BaseNewsCell {
// Put here things that are ONLY for ProjectNewsCell
}
然后通过两个不同的故事板单元xibs从2个不同的标识符中取消它们。
或者
class BaseNewsCell: UITableViewCell {
// Put the common views here
}
class OrganizationNewsCell: BaseNewsCell {
// This happens when this kind of cell is created for the first time
override func awakeFromNib() {
super.awakeFromNib()
someNonCommon.removeFromSuperview()
}
}
class ProjectNewsCell: BaseNewsCell {
override func awakeFromNib() {
super.awakeFromNib()
someOtherNonCommon.removeFromSuperview()
}
}
注意: 这违反了Liskov的原则(SOLID原则之一),因为您从子类中的超类中删除了功能。
答案 2 :(得分:0)
您不应该从单元格的外部中删除子视图。让我们重构您的代码。
<强> NewsCell.swift 强>
final class NewsCell: UITableViewCell {
enum Kind {
case organization
case project
}
var logoImageView: UIImageView?
let nameLabel = UILabel()
var kind: NewsCell.Kind {
didSet {
if kind != oldValue {
setupLogoImageView()
self.setNeedsLayout()
}
}
}
init(kind: NewsCell.Kind, reuseIdentifier: String?) {
self.kind = kind
super.init(style: .default, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - Positioning
extension NewsCell {
override func layoutSubviews() {
super.layoutSubviews()
// Your layouting
switch kind {
case .organization:
// Setup frame for organization typed NewsCell
case .project:
// Setup frame for project typed NewsCell
}
}
}
// MARK: - Setup
extension NewsCell {
private func setupLogoImageView() {
logoImageView = kind == .organization ? UIImageView() : nil
}
}
使用方法:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let news = newsCollection[indexPath.row]
var cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellIdentifiers.newsCell) as? NewsCell
if cell == nil {
cell = NewsCell(kind: .organization, reuseIdentifier: TableViewCellIdentifiers.newsCell)
}
cell!.kind = news is Organization ? .organization: .project
return cell!
}