Требуется ли быстрое подкласс * всегда * вызвать super.init()
Если у меня есть быстрый подкласс, который:
- не требуется доступ к
self
- не требуется доступ к каким-либо свойствам на
self
Должен ли я по-прежнему вызывать super.init()
в подклассе init()
метод?
* Примечание. Это другой вопрос, чем тот, который был задан, и ответил здесь на SO из-за особенностей, перечисленных в 1 и 2 выше.
Ответы
Ответ 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.