将 IBOutlets 用于 UIView 时,如何在初始化期间引用自身?

How can I refer to self during initialization when using IBOutlets for UIViews?

我有这个自定义 UITableViewCell class 在 table 视图中支持我的单元格(我从在 Apple 的 UIKit 团队工作的 Andy Matuschak 的一次演讲中学到了这种方法)。

在我尝试将此应用到现在的项目中,我在初始化 class 时遇到问题,因为有几个 @IBOutlets 链接到 UIView永远不会有像 UILabels 这样的值的元素在初始化时得到:

class PublicationTableViewCell: UITableViewCell {

  @IBOutlet weak var publicationTitle: UILabel!
  @IBOutlet weak var authorName: UILabel!
  @IBOutlet weak var pubTypeBadgeView: UIView!
  @IBOutlet weak var pubTypeBadge: UILabel!
  @IBOutlet weak var topHighlightGradientStackView: UIStackView!
  @IBOutlet weak var bottomBorder: UIView!

  struct ViewData {
    let publicationTitle: UILabel
    let authorName: UILabel
    let pubTypeBadge: UILabel
  }

  var viewData: ViewData! {
    didSet {
      publicationTitle = viewData.publicationTitle
      authorName = viewData.authorName
      pubTypeBadge = viewData.pubTypeBadge
    }

  // I have @IBOutlets linked to the views so I can do this:
  override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    super.setHighlighted(highlighted, animated: animated)

    if isSelected || isHighlighted {
      topHighlightGradientStackView.isHidden = true
      bottomBorder.backgroundColor = UIColor.lightGrey1
    } else {
      topHighlightGradientStackView.isHidden = false
    }
  }
}

extension PublicationTableViewCell.ViewData {
  init(with publication: PublicationModel) {

    // Xcode complains here about referring to the properties 
    // on the left before all stored properties are initialized

    publicationTitle.text = publication.title
    authorName.text = publication.formattedAuthor.name
    pubTypeBadge.attributedText = publication.pubTypeBadge
  }
}

然后我在 cellForRow 中通过传递这样的发布来初始化它:

cell.viewData = PublicationTableViewCell.ViewData(with: publication)

Xcode 抱怨我在 init(with publication: PublicationModel) 中使用 self 之前我理解所有存储的属性被初始化,但我不知道如何修复。

如果这些不是 UIView 属性,我可能会将它们设为可选属性或计算属性,但因为这些是 IBOutlet,我认为它们需要隐式展开可选属性。

还有其他方法可以让它工作吗?

首先:

struct ViewData {
   let publicationTitle: String
   let authorName: String
   let pubTypeBadge: NSAttributedString
}

然后简单地:

extension PublicationTableViewCell.ViewData {
  init(with publication: PublicationModel) 
    publicationTitle = publication.title
    authorName = publication.formattedAuthor.name
    pubTypeBadge = publication.pubTypeBadge
  }
} 

这是一个数据模型,它不应该包含 views,它应该只包含 data.

然后:

var viewData: ViewData! {
    didSet {
       publicationTitle.text = viewData.publicationTitle
       authorName.text = viewData.authorName
       pubTypeBadge.attributedString = viewData.pubTypeBadge
   }
}

但是,我认为如果您只是将 PublicationModel 作为您的单元格数据传递会更简单。没有理由将其转换为另一个 struct.

var viewData: PublicationModel! {
    didSet {
       publicationTitle.text = viewData.publicationTitle
       authorName.text = viewData.authorName
       pubTypeBadge.attributedString = viewData.pubTypeBadge
   }
}