子类内部的结构,分配给自身时解包可选

Struct inside subclass, unwrap optional when assigning to self

老实说,我找不到更好的标题了,所以如果有人能提出更有意义的建议,那就太好了。

前段时间我看到很棒的演讲 来玩吧:重构 Mega Controller! Andy Matuschak 的演讲。他展示了很好的模式:使用 struct 将数据注入视图,将视图的内部结构与视图控制器分离。 它是这样的:

class TaskTableViewCell: UITableViewCell {
    struct ViewData {
        let title: String
        let timingDescription: String
    }

    var viewData: ViewData? {
        didSet {
            textLabel!.text = viewData?.title
            detailTextLabel!.text = viewData?.timingDescription.lowercaseString
        }
    }
}

现在如您所见,在 viewDatadidSet 中,我们更新了 TaskTableViewCelltextLabeldetailTextLabel。好吧,实际上是 UITableViewCell 因为它们都是继承的属性。

但这是基本的 table 视图单元格,我想要定制的东西。我已经添加了 someText 属性,并且需要初始化。现在,class 看起来如下:

class TaskTableViewCell: UITableViewCell {
    struct ViewData {
        let title: String
        let timingDescription: String
    }

    var viewData: ViewData? {
        didSet {
            textLabel!.text = viewData?.title
            detailTextLabel!.text = viewData?.timingDescription.lowercaseString
        }
    }

    var someText: String

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        someText = ""
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

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

当然我想更新 someText,比方说用 ViewData 结构的 title 属性。

/// In didSet
someText = viewData?.title

这给了我以下错误:

TaskTableViewCell.swift:21:34: Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?

这很奇怪,因为在 TaskTableViewCellViewData 中都没有可选的字符串。 我可以解决这个问题 someText = (viewData?.title)! 或者 someText = viewData!.title 但我想避免 force-unwrapping.

你能给我解释一下这是怎么回事吗?

以及为什么编译器在分配给继承 属性 时不打印错误?

但有一个可选的

someText 不是可选的,但 viewData

var viewData: ViewData?,这就是你被迫解包的原因。

你可以这样避免:

someText = viewData?.title ?? "defaultValue"
//equivalent to 
someText = viewData?.title == nil ? "defaultValue" : (viewData?.title)!
someText = viewData?.title

someText不可选,属性struct中的title不可选,但是struct viewData的实例是可选的,所以viewData的title是可选的。所以编译器会给出错误。

UILable 的属性 文本是可选的,默认值为零。所以
textLabel!.text = viewData?.title 可以。