从单元格中的超级视图中删除视图
Posted
技术标签:
【中文标题】从单元格中的超级视图中删除视图【英文标题】:Removing views from superview in cell 【发布时间】:2018-06-18 18:08:57 【问题描述】:我有一个单元类“NewsCell”(UITableViewCell 的子类),用于两种不同类型的新闻:OrganizationNews 和 ProjectNews。这些新闻有共同的东西,但有些元素是不同的。也就是说,当我的单元格用于 ProjectNews 时,我想隐藏组织的徽标,当它用于 OrganizationNews 时,我想隐藏项目的名称按钮。
我有 'configureCell(_, forNews, ofProject)' 方法。我在“NewsViewController”中调用它。我使用了“removeFromSuperview”方法,因为我需要重新排列“NewsCell”中的元素。改变 'isHidden' 的值不会给我那种效果。
所以,这就是问题所在。我在 projectNameButton.removeFromSuperview() 或 logoImageView.removeFromSuperview() 行中有“线程 1:致命错误:在展开可选值时意外发现 nil”异常。 我该怎么办?
// 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
【问题讨论】:
这只是故事板的出口。 IBOutlet 弱 var logoImageView: UIImageView!和 IBOutlet 弱 var projectNameButton: UIButton! 要么使用两个不同的单元格类,要么将逻辑显示在单元格类中,而不是在视图控制器中。 @rmaddy 当这个“配置”方法在单元类中时,我遇到了同样的问题。 您的网点未连接。 【参考方案1】:UITableView 或 UICollectionView 建立在 reuse 概念之上,当您处理它时,单元格会被重用和重新填充。
当您尝试调用dequeReusableCell(withIdentifier:)
时,它有时会返回之前创建的内容。因此,假设您在具有所有控件的东西之前先出队,然后删除了一个(removeFromSuperview
),然后再次尝试出队,新出队的人可能没有子视图。
我认为对你来说最好的解决方案是制造两个不同的细胞。
示例:
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】:如下改变删除线,
if news is OrganizationNews
cell.projectNameButton?.removeFromSuperview()
else if news is ProjectNews
cell.logoImageView?.removeFromSuperview()
这将解决问题。但一个好的方法是为每个单元创建单独的类。您可以创建一个基类来保留公共逻辑。
【讨论】:
这样可以避免崩溃。它不能解决问题的原因。【参考方案3】:您不应该从单元格的外部移除子视图。让我们重构您的代码。
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!
【讨论】:
以上是关于从单元格中的超级视图中删除视图的主要内容,如果未能解决你的问题,请参考以下文章