I have this custom UITableViewCell class backing my cells in a table view (I learned this approach from a talk by Andy Matuschak who worked at Apple on the UIKit team).
In the project I'm trying to apply this to now, I'm having a problem initializing the class because of a couple of @IBOutlets
that are linked to UIView
elements that won't ever have values like the UILabel
s get upon initialization:
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
}
}
I then initialize it in cellForRow
by passing in a publication like this:
cell.viewData = PublicationTableViewCell.ViewData(with: publication)
Xcode is complaining that I'm using self
in init(with publication: PublicationModel)
before all stored properties are initialized which I understand, but I can't figure out how to fix.
If these weren't UIView
properties I might make them optional or computed properties perhaps, but because these are IBOutlet
s, I think they need to be implicitly unwrapped optionals.
Is there some other way I can get this to work?
First of all:
struct ViewData {
let publicationTitle: String
let authorName: String
let pubTypeBadge: NSAttributedString
}
Then simply:
extension PublicationTableViewCell.ViewData {
init(with publication: PublicationModel)
publicationTitle = publication.title
authorName = publication.formattedAuthor.name
pubTypeBadge = publication.pubTypeBadge
}
}
It's a data model, it shouldn't hold views, it should hold only data.
Then:
var viewData: ViewData! {
didSet {
publicationTitle.text = viewData.publicationTitle
authorName.text = viewData.authorName
pubTypeBadge.attributedString = viewData.pubTypeBadge
}
}
However, I think it would be simpler if you just passed PublicationModel
as your cell data. There is no reason to convert it to another struct
.
var viewData: PublicationModel! {
didSet {
publicationTitle.text = viewData.publicationTitle
authorName.text = viewData.authorName
pubTypeBadge.attributedString = viewData.pubTypeBadge
}
}