为什么我在Swift中初始化变量的行上得到"在初始化之前使用的变量"错误?

ran*_*eur 41 ios swift

我很难理解为什么我在使用Swift的iOS项目中遇到此编译器错误.如果我创建以下类:

class InitTest {

    let a: Int
    let b: Int
    let c: Int

    init () {
        self.a = 3
        self.b = 4
        self.c = self.runCalculation()
    }

    func runCalculation () -> Int {
        return self.a * self.b
    }
}
Run Code Online (Sandbox Code Playgroud)

我在行上写了一个编译错误,self.c = self.runCalculation()说"在初始化之前使用了变量'self.c'".

起初我以为这是因为编译器无法验证该runCalculation()方法无法访问self.c,但后来我尝试将init方法稍微混合起来:

init () {
    self.a = 3
    self.c = self.runCalculation()
    self.b = 4
}
Run Code Online (Sandbox Code Playgroud)

这次错误是"初始化之前使用的变量'self.b'"(在同一self.runCalculation()行).这表明编译器能够检查其性能的方法访问,所以据我可以看到应该有最初的情况下,没有问题的.

当然这是一个简单的例子,我可以轻松地重构以避免调用计算方法,但在一个真实的项目中,可能会有几个计算,每个计算都可能非常复杂.我希望能够分离逻辑以保持可读性.

幸运的是,有一个简单的解决方法:

init () {
    self.a = 3
    self.b = 4

    self.c = 0
    self.c = self.runCalculation()
}
Run Code Online (Sandbox Code Playgroud)

(或使用属性初始化程序let c = 0)但我想了解编译器第一个示例存在问题的原因.我错过了什么或是不必要的限制?

Kir*_*ins 46

由于两阶段初始化,Swift具有这种行为.来自Apple的Swift书:

Swift中的类初始化是一个两阶段的过程.在第一阶段,每个存储的属性都由引入它的类分配初始值.一旦确定了每个存储属性的初始状态,第二阶段就开始了,并且每个类都有机会在新实例被认为可以使用之前进一步定制其存储的属性.

在第一阶段结束之前,类需要某种默认值.定制值是第二阶段的一部分.

Objective-C没有这种行为,因为它总是可以0为基元和nil对象提供默认值,但是在Swift中没有提供这种默认值的机制.

  • @rankAmateur:一个方法可以在子类中重写(它假定超类属性被完全初始化). (6认同)
  • @MartinR好点.对手册的引用的任何评论`初始化器不能调用任何实例方法,读取任何实例属性的值,或者在初始化的第一阶段完成之前将self作为值引用? (5认同)