【问题标题】:Convenience Init For UICollectionViewCellUICollectionViewCell 的便利初始化
【发布时间】:2023-02-18 16:07:00
【问题描述】:

我有一个自定义的UICollectionViewCell,我在整个项目的两个地方使用它。

两个UICollectionViewCell除了显示UIButton之外是相同的。为了减少代码重复,我想在两个地方都使用单元格,但用一个布尔值初始化一个,以确定是否显示按钮。

我相信我需要一个便利的初始值设定项来执行此操作,但是,我收到了错误;

在“self.init”调用或赋值给“self”之前使用“self”

代码:

class MediaSelectionCell: UICollectionViewCell {
    
    var withDeleteButton = false
    
    convenience init(showsDeleteButton: Bool) {
        self.init(showsDeleteButton: withDeleteButton)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

我该如何解决这个问题?

【问题讨论】:

  • 单元格被重复使用,并且无需您的方法即可调用。相反,在 cellForRow 中,将 didSet 添加到 withDeleteButton 以隐藏/显示按钮。
  • @Larme 单元格用于应用程序的不同部分,要么所有单元格都有按钮,要么没有,所以我认为 didSet 在这里并不是很有用。除非我遗漏了什么。
  • @DavidHenry - 你不能那样初始化单元格。您要么需要设置隐藏在cellForItemAt 中的按钮,要么创建两个单元格类(子类化“基本”单元格可能是使用该方法的方法)。

标签: ios swift xcode initialization uicollectionviewcell


【解决方案1】:

您的 collectionview 单元格初始化没有名为 self.init(showsDeleteButton: withDeleteButton) 的方法,这就是您收到错误消息的原因。

正如评论中所说,细胞是可重复使用的。如果你用故事板注册单元格, required init?(coder: NSCoder)调用初始化方法,如果你以编程方式注册单元格 override init(frame: CGRect)被调用。

所以我的意思是,如果你使用dequeueReusableCell,你不能手动更改初始化方法。

我更喜欢创建两个类来做你想做的事:

一个不显示按钮:

class MediaSelectionCell: UICollectionViewCell {

var withDeleteButton = false
   
      override init(frame: CGRect) {
       super.init(frame: frame)
       // maybe adding constraint your bla bla
       
   }

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

   func controlButton() -> Bool{
      if withDeleteButton{
         // show
         return true
     }else{
         // hide
         return false
     }
  }
 }

一个用于显示按钮:

class MediaSelectionShowButton : MediaSelectionCell{
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.withDeleteButton = true
    }

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

在你的牢房里,你可以控制它并做你想做的事:

cell.controlButton()

【讨论】:

  • 这个答案的第一段是错误的。 MediaSelectionCell 类确实有一个 init(showsDeleteButton: withDeleteButton)。它显示在问题中。问题中显示的错误来自于在对self.init(showsDeleteButton: withDeleteButton) 的调用中尝试访问self.withDeleteButton(隐式使用self)。 init方法应该先做self.withDeleteButton = withDeleteButton,然后调用super.init()。但这也意味着 init(showsDeleteButton: withDeleteButton) 不能是便利的初始值设定项。
  • 说了这么多,这个答案的第 2 段和第 3 段正确地指出了更大的问题。但是,此答案中显示的 override init(frame) 代码也是错误的。它会尝试在 withDeleteButton 的值可能被设置为超出默认值之前对其进行操作。
  • 题中没有指定初始化名为self.init(showsDeleteButton: withDeleteButton)?即使是,当你对第一条评论说 2 时你是对的。感谢你的第二条评论。你是对的。在子类中将 withDeleteButton 设置为 true 并在基类 init 中做一些事情是没有意义的。
【解决方案2】:

您不能对表视图或集合视图单元格使用便利初始化程序,因为表视图/集合视图通过调用指定的初始化程序来创建它们。

您必须向自定义类添加一个属性并将其设置为支持该属性。

【讨论】:

  • 仅当单元格设置在故事板中或您将单元格注册到表/集合视图时才会出现这种情况。我从不这样做,我的自定义单元格都有自定义的 init 方法,它们工作得很好。但是,自定义 init 不需要成为便利初始化程序。在 OP 的情况下,这是一个错误。它应该是一个普通的init调用了一个合适的super.init
  • 如果您既不在表视图中注册单元格类也不注册故事板/nibfile,dequeue 方法如何创建新的单元格?
  • 或者你让它返回 nil 然后调用你的自定义初始化程序?
  • 就是这样 - 让 dequeue 返回 nil,然后我调用自定义 init。类似于:let cell = tableView.dequeueReusableCell(withIdentifier: "myId") as? MyCell ?? MyCell(reuseIdentifier: "myId", otherParams: otherValues)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 1970-01-01
相关资源
最近更新 更多