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

Требуется ли быстрое подкласс * всегда * вызвать super.init()

Если у меня есть быстрый подкласс, который:

  • не требуется доступ к self
  • не требуется доступ к каким-либо свойствам на self

Должен ли я по-прежнему вызывать super.init() в подклассе init() метод?

* Примечание. Это другой вопрос, чем тот, который был задан, и ответил здесь на SO из-за особенностей, перечисленных в 1 и 2 выше.

4b9b3361

Ответ 1

Нет, вам не обязательно.

Предположим, что у вас есть следующие классы.

class a {
    let name: String

    init() {
        name = "james"
    }
}

class b: a {
    let title: String

    override init() {
        title = "supervisor"
    }
}

Если вы создаете экземпляр переменной с помощью

let myVar = b()

Затем

  • override init() в b будет называться
  • то init() в a будет называться

Даже если вы явно не вызывали super.init().


Это подтвердил Крис Лайтнер в списке адресов быстрого пользователя. Он запускается, когда ваш суперкласс имеет один назначенный инициализатор с инициализацией нуля. Вот почему вам не нужно вызывать super.init() при получении из NSObject.

* Благодаря комментарию Wingzero ниже

Ответ 2

Из документов:

Назначенные инициализаторы должны вызывать назначенный инициализатор из своего непосредственного суперкласса.

Кроме того, что касается автоматического наследования инициализатора:

Предполагая, что вы предоставляете значения по умолчанию для любых новых свойств, вы ввести в подкласс, применяются следующие два правила:

Правило 1 Если ваш подкласс не определяет какие-либо назначенные инициализаторы, он автоматически наследует все его инициализаторы, назначенные суперклассам.

Правило 2 Если ваш подкласс обеспечивает реализацию всех его суперклассы, назначенные инициализаторы, либо путем наследования их в соответствии с правило 1, или путем предоставления пользовательской реализации как части ее определение - тогда он автоматически наследует все суперклассы инициализаторы удобства.

Эти правила применяются, даже если ваш подкласс добавляет дополнительное удобство Инициализаторы.

Итак, ответ на ваш вопрос таков:

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

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

Это означает, что вы должны абсолютно первыми в каждом init() установить свои переменные, а затем вы можете вызвать (или не) super.init() и запустить собственный код. Итак, как вы сказали выше, если вы хотите, чтобы супер init запускался в начале, рассмотрите "начало" сразу после создания ваших переменных:

class a {
    var name: String

    init() {
        name = "james"
        println("a")
    }
}

class b: a {
    let title: String

    override init() {
        title = "supervisor"
        super.init()
        self.name = "john"
        println("b")
    }
}

let x = b()

Это напечатает a, затем b.

Ответ 3

Да назначенный инициализатор должен делегировать, поэтому он должен вызвать super.init(). Если вы не пишете строку, компилятор сделает это за вас.

Таким образом, вам не нужно явно писать super.init(...), но подкласс должен, даже если только за занавеской.

Но помните, что на первом этапе вам нужно установить свойства в подклассе, а затем вызвать super.init(). На втором этапе вы можете изменить все унаследованные свойства. Я думаю, что super.init() - идеальный разделитель между фазой 1 и фазой 2.

Из документов:

Проверка безопасности 2

A назначенный инициализатор должен делегировать в инициализатор суперкласса перед назначением значения унаследованному свойству. Если он не делает, новое значение, назначенное назначенным инициализатором, будет перезаписано суперклассом как часть его собственной инициализации.

Ответ 4

Я думаю, вам не нужно называть супер. Я попытался имитировать ситуацию следующим образом:

class Animal {
}

class Parrot: Animal {

    override init() {
        // Some code (super not called)
    }
}

Однако я бы рекомендовал всегда называть super.init в реальном приложении, как вы это делаете в Objective-C.