为啥我们需要 dequeueReusableCell func 获得的向上转换单元格?

Posted

技术标签:

【中文标题】为啥我们需要 dequeueReusableCell func 获得的向上转换单元格?【英文标题】:Why do we need upcasting cell obtained by dequeueReusableCell func?为什么我们需要 dequeueReusableCell func 获得的向上转换单元格? 【发布时间】:2018-01-17 10:56:25 【问题描述】:

我很困惑

 override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MessageCell
    if let message = messages?[indexPath.item] 
        cell.message = message
    
    cell.timeLibel
    return cell

我应该将单元格向上转换为由重用标识符隐含的类。所以事实证明(在我的情况下) deqeueReusableCell 函数的结果不是 MessageCell 类,即使我已经完全注册了它

 collectionView?.register(MessageCell.self, forCellWithReuseIdentifier: cellId)

此外,当我尝试查看它是不是真的 MessageCell 实例时

cell.isKind(of: MessageCell.self)

它返回真。但与此同时,当我尝试访问 MessageCell 类的实例属性时,它会引发错误“'UICollectionViewCell' 类型的值没有成员'消息”

但是参考说:

在您的委托方法中将适当的视图出列后, 配置其内容并返回到collection view中使用。

以及来自 UICollectionViewDataSource 的参考:

您对此方法的实现负责创建, 配置并返回给定项目的适当单元格。 您可以通过调用 集合的 dequeueReusableCell(withReuseIdentifier:for:) 方法 查看并传递对应于单元格的重用标识符 输入你想要的。

为什么我们需要向上转型 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) ?

这里是 MessageCell 等

 class MessageCell: BaseCell 
var message: Message? 
    didSet 
        nameLabel.text = message?.friend?.name
        if let profileImageName = message?.friend?.profileImageName 
            profileImageView.image = UIImage(named: profileImageName)
            messageLabel.text = message?.text
        
    

let profileImageView: UIImageView = 
    let imageView = UIImageView()
    imageView.contentMode = .scaleAspectFill
    imageView.layer.cornerRadius = 34
    imageView.layer.masksToBounds = true

    return imageView
()

let dividerLineView: UIView = 
    let view = UIView()
    view.backgroundColor = UIColor(white: 0.5, alpha: 0.5)
    return view
()
    let nameLabel: UILabel = 
    let label = UILabel()
    label.text = "Mark Zuckerberg"
    label.font = UIFont.systemFont(ofSize: 18)
//    label.backgroundColor = UIColor.brown
    return label
()

let messageLabel: UILabel = 
    let label = UILabel()
    label.text = "Your friends message and something else..."
    label.textColor = UIColor.darkGray
    label.font = UIFont.systemFont(ofSize: 14)
//    label.backgroundColor = UIColor.green
    return label
()


let timelabel : UILabel = 
    let label = UILabel()
    label.text = "12:05 pm"
    label.font = UIFont.systemFont(ofSize: 16)
    label.textAlignment = .right
//    label.textColor = UIColor.white
//    label.backgroundColor = UIColor.black
    return label

()

let hasReadImageView: UIImageView = 
    let imageView = UIImageView()
   imageView.contentMode = .scaleAspectFill
    imageView.layer.cornerRadius = 10
    imageView.layer.masksToBounds = true

    return imageView
()
override func setupViews() 

    addSubview(profileImageView)
     addSubview(dividerLineView)
    profileImageView.image = UIImage(named: "zuckprofile")
    hasReadImageView.image = UIImage(named: "zuckprofile")
    setupContainerView()

    addConstraintsWithFormat( "H:|-12-[v0(68)]|", views: profileImageView)
    addConstraintsWithFormat( "V:[v0(68)]", views: profileImageView)
    addConstraint(NSLayoutConstraint(item: profileImageView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0))
    addConstraintsWithFormat( "H:|-82-[v0]|", views: dividerLineView)
    addConstraintsWithFormat( "V:[v0(1)]|", views: dividerLineView)




func setupContainerView() 
    let containerView = UIView()
     addSubview(containerView)

    addConstraintsWithFormat("H:|-90-[v0]|", views: containerView)
    addConstraintsWithFormat(  "V:[v0(50)]", views: containerView)
    addConstraint(NSLayoutConstraint(item: containerView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0))
    containerView.addSubview(nameLabel)
    containerView.addSubview(messageLabel)
    containerView.addSubview(timelabel)
    containerView.addSubview(hasReadImageView)
    containerView.addConstraintsWithFormat( "H:|[v0][v1(80)]-12-|", views: nameLabel, timelabel )
    containerView.addConstraintsWithFormat( "V:|[v0(26)][v1(24)]|", views: nameLabel,messageLabel )
    containerView.addConstraintsWithFormat( "H:|[v0]-8-[v1(20)]-12-|", views: messageLabel, hasReadImageView )
    containerView.addConstraintsWithFormat("V:[v0(20)]|", views: hasReadImageView)
    containerView.addConstraintsWithFormat( "V:|[v0(24)]", views: timelabel)
   addConstraint(NSLayoutConstraint(item: nameLabel, attribute: .centerY, relatedBy: .equal, toItem: timelabel, attribute: .centerY, multiplier: 1, constant: -1.4 ))








 extension UIView 
func addConstraintsWithFormat(_ format: String , views: UIView...) 
    var viewsDictionary = [String: UIView]()
    for (index, view) in views.enumerated() 
        let key = "v\(index)"
        viewsDictionary[key] = view
        view.translatesAutoresizingMaskIntoConstraints = false
    
    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary))





 class BaseCell : UICollectionViewCell 
let a = 5
override init(frame: CGRect) 
    super.init(frame: frame)
    setupViews()
    layer.masksToBounds = true

required init?(coder aDecoder: NSCoder) 
    fatalError("init(coder:) has not been implemented")


func setupViews() 
    backgroundColor = UIColor.blue


 

【问题讨论】:

如果我没记错的话,isKindOf 将检查对象是否可以成功转换为该类型。但它实际上并没有那样投射。您需要自己执行此操作,因为只有您会知道您为该重用标识符注册了什么类型 请再看看我的问题 isKind(of:) 返回一个布尔值,指示接收者是给定类的实例还是从该类继承的任何类的实例。 MessageCell 长什么样子? 这是在构建时和运行时发生的区别。 dequeue 函数的定义说它返回一个 UICollectionView 单元格,这意味着它也可以是 MessageCell 的子类。因此,在构建时,编译器不知道要返回什么(没有进行编译来确定这一点),因此您必须向下转换为正确的类型。然而,在运行时,系统确切地知道它是什么,因此可以确定正确的类型。 【参考方案1】:

dequeueReusable 用于提高内存效率。它在较低级别的工作方式我的朋友对此有详细的解释https://medium.com/ios-seminar/why-we-use-dequeuereusablecellwithidentifier-ce7fd97cde8e

我希望它回答了你的问题。

【讨论】:

以上是关于为啥我们需要 dequeueReusableCell func 获得的向上转换单元格?的主要内容,如果未能解决你的问题,请参考以下文章

dequeueReusableCell 之后的单元格布局

iOS:UICollectionView 内容重置和 dequeueReusableCell

如何使用 tableView.dequeueReusableCell 以编程方式将单元格样式添加到单元格?

如何在 UITableView 中实现 dequeueReusableCell(withIdentifier:) 的代码?

dequeueReusableCell 打破了cliptobounds

如何在不弄乱内容的情况下标记 dequeueReusableCell?