Swift类没有初始值设定项,但是有属性观察者

问题描述:

我刚开始学习swift并对类初始值设定项有疑问。这里是我的示例代码: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 

我想使用属性观察者。当我隐式解开属性观察者类型是结构时,一切正常。否则,它说:“类没有初始化。我很困惑,我为什么要暗中提前解开结构。谢谢!

这不完全是从你的问题不清楚,但我相信你会问,为什么你不能替换此:

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!时,你的意思是“它可能为零,但如果有人试图读取它虽然是零,那么这是一个可怕的灾难,我的整个应用程序应该崩溃。”因此,斯威夫特将TV初始化为res设为零,并且期望您将其设置为其他值。

然而,当属性的类型为Resolution,你说,“它不能永远是零,没有过,即使是在没有人看。”这意味着,res必须已经从一个值TV被实例化的时刻。但是,这个价值应该是什么?没有默认设置。你有两个选择,如果类型为Resolution

  1. 使用属性初始化它设置一些默认值(这是它看起来就像你正在试图做的):

    class TV { 
        var res: Resolution = Resolution(width: 1, height: 1) 
    } 
    

    ...或与初始化,可以让斯威夫特推断类型:

    class TV { 
        var res = Resolution(width: 1, height: 1) 
    } 
    
  2. 询问谁是创造了TV时instan指定初始值tiating类:

    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是一个结构,然后斯威夫特产生init(res:)对你来说确实与结构,但不带班。)

的第三种选择是使类型Resolution?

class TV { 
    var res: Resolution? { 
    didSet { 
     res?.width = 1 
     res?.height = 1 
    } 
    } 
} 

这是一个更好的选择,而不是Resolution!,这仅仅是一个等待发生崩溃。隐含的解包选择权应该是最后的手段,可以在非常具体的,仔细考虑的情况下使用。

+0

非常感谢!现在我明白了什么是“!”和初始化程序。 – artemchen

每个实例变量必须初始化结束时间有一个值。

  • 如果不使用可选的,那么你必须在这里提供一个实际的解决方案实例作为res价值 - 和你不这样做,

  • 如果你使用一个可选的编译器提供nil作为值,因此需要满足一个值。

一种可能性是写你的类是这样的:

类电视{VAR 解析度=分辨率(){ didSet { res.width = 1个 res.height = 1 }} }

现在res有一个初始值:即实际的Resolution实例。

但是你在做什么是没有错。当您知道在初始化时无法为实例变量提供值时,使用“可选”非常常见,但您打算在后面提供一个值。

+0

读我的书可能会有所帮助:http://www.apeth.com/swiftBook/ch04.html#_initializers – matt