您的问题并不完全清楚,但我假设您在问为什么不能替换它:
var res: Resolution! {
…用这个:
var res: Resolution {
您的线索来自完整的编译器错误消息,您可以通过查看编译器日志(或游乐场控制台,如果您在游乐场)来查看:
error: class 'TV' has no initializers
class TV {
^
note: stored property 'res' without initial value prevents synthesized initializers
var res: Resolution {
^
error: 'TV' cannot be constructed because it has no accessible initializers
var television = TV()
当属性的类型是Resolution! 时,你是在说,“它可以是 nil,但如果有人试图在它为 nil 时读取它,那将是一场可怕的灾难,我的整个应用程序应该崩溃。”因此 Swift 初始化 TV 并将 res 设置为 nil,并希望您立即将其设置为其他值。
但是,当属性的类型是 Resolution 时,您是在说,“它永远不能为 nil,永远不能,即使没有人在看也不能。”这意味着res 必须从TV 被实例化的那一刻起就有一个值。但是这个值应该是多少?没有默认设置。如果类型是Resolution,你有两种选择:
-
使用属性初始值设定项将其设置为某个默认值(这看起来就像您正在尝试做的那样):
class TV {
var res: Resolution = Resolution(width: 1, height: 1)
}
…或者使用初始化器,你可以让 Swift 推断类型:
class TV {
var res = Resolution(width: 1, height: 1)
}
-
请创建TV 的人在实例化类时指定初始值:
class TV {
init(res: Resolution) {
self.res = res
}
var res: Resolution {
didSet {
res.width = 1
res.height = 1
}
}
}
var resolution = Resolution()
var television = TV(res: resolution)
除此之外:所有这些都完全没有意义,因为您在设置分辨率后立即将宽度和高度更改为 1(什么?!),但它确实可以编译。
那么来自编译器的“综合初始化器”消息? Swift 会自动为你的类创建一个空的init(),但如果有任何非可选属性要初始化,则不会。如果有,您必须编写自己的初始化程序。
(请注意,如果 TV 是一个结构,那么 Swift 会为您生成 init(res:)。它适用于结构,但不适用于类。)
第三种选择是使类型Resolution?:
class TV {
var res: Resolution? {
didSet {
res?.width = 1
res?.height = 1
}
}
}
这比 Resolution! 更好,后者只是等待发生的崩溃。隐式解包选项应该只是最后的手段,在非常具体、经过仔细考虑的情况下使用。