Подтвердить что ты не робот

Почему я получаю сообщение "Переменная, используемая до инициализации" в строке, в которой я инициализирую переменную в Swift?

Я пытаюсь понять, почему я получаю эту ошибку компилятора в проекте iOS с помощью Swift. Если я создам следующий класс:

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
    }
}

Я получаю ошибку компилятора в строке self.c = self.runCalculation(), говорящую "Variable" self.c ', которая использовалась до инициализации ".

Сначала я думал, что это связано с тем, что компилятор не смог проверить, что метод runCalculation() не имел доступа к self.c, но затем я попытался немного смешать метод init:

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

и на этот раз ошибка "Variable" self.b 'используется до инициализации "(в той же строке self.runCalculation()). Это указывает на то, что компилятор способен проверять, к каким свойствам обращается метод, и насколько я могу видеть, не должен иметь проблемы с начальным случаем.

Конечно, это тривиальный пример, и я мог бы легко реорганизовать, чтобы избежать вызова метода расчета, но в реальном проекте может быть несколько расчетов, каждый из которых может быть весьма вовлекающим. Я хотел бы иметь возможность отделить логику, чтобы сохранить читаемость.

К счастью, существует простой способ:

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

    self.c = 0
    self.c = self.runCalculation()
}

(или используя инициализатор свойств let c = 0), но я хотел бы понять, почему у компилятора есть проблема с первым примером. Я что-то упускаю или это лишнее ограничение?

4b9b3361

Ответ 1

Свифт имеет такое поведение из-за двухфазной инициализации. Из книги Apple Swift:

Инициализация классов в Swift является двухфазным процессом. Во-первых фазе, каждому сохраненному свойству присваивается начальное значение классом который представил его. Как только начальное состояние для каждого сохраненного имущества было определено, начинается вторая фаза, и каждому классу дается возможность настроить свои сохраненные свойства еще до новый экземпляр считается готовым к использованию.

Классу требуется какое-то значение по умолчанию перед завершением первой фазы. Пользовательские значения являются частью второй фазы.

Objective-C не выполнял этого поведения, потому что он всегда мог указывать 0 по умолчанию для примитивов и nil для объектов, но в Swift нет механизма для предоставления такого значения по умолчанию.