我刚开始学习 swift,对类初始化器有疑问。这是我的示例代码:
struct Resolution {
var width = 0
var height = 0
}
let someResolution = Resolution()
class TV {
var res: Resolution! {
didSet {
res.width = 1
res.height = 1
}
}
}
var television = TV()
var resolution = Resolution()
television.res = resolution
我正在尝试使用属性观察器。当我隐式解包 struct 属性观察者类型时,一切正常。否则,它会说“类没有初始化器。我很困惑为什么我应该隐式解包结构。提前致谢!
最佳答案
从你的问题来看还不是很清楚,但我想你是在问为什么你不能替换这个:
var res: Resolution! {
...有了这个:
var res: Resolution {
您的线索来自完整的编译器错误消息,您可以通过查看编译器日志(如果您在 playground 中,则可以查看 playground 控制台):
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
时,您是在说,“它永远不可能为零,永远不会,即使没有人在看。”这意味着 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!
更好的选择,后者只是等待发生的崩溃。隐式解包选项应该只是最后的手段,在非常具体、经过仔细考虑的情况下使用。
关于ios - 没有初始化器但有属性观察器的 Swift 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33558409/