Почему вызов super.init() вызывает мою стандартную init ()

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

В моем назначенном init я вызываю super.init()

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

Книга говорит:

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

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

Так что я не уверен, что все изменилось или я делаю что-то не так?

Код:

class ORQuizViewController: UIViewController {
let imageView: UIImageView = UIImageView(image: nil)
let questionLabel: UILabel = UILabel()
let choicesArray: [BlackWhiteButton] = [BlackWhiteButton]()
let correctAnswer: Int = -1

init(image: UIImage!, question: String, choices: [String], answerIndex: Int) {
    super.init()
    imageView = UIImageView(image:image)
    questionLabel = UILabel()
    questionLabel.text = question
    var tempChoices = [BlackWhiteButton]()
    for choice in choices {
        var choiceLabel = BlackWhiteButton()
        choiceLabel.setTitle(choice, forState: .Normal)
        tempChoices.append(choiceLabel)
    }
    choicesArray = tempChoices
    correctAnswer = answerIndex
}

2 ответа

Решение

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

Проверка безопасности 1 применяется во время фазы 1 процесса инициализации.

Затем происходит фаза 2 процесса инициализации -

Фаза 2

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

Таким образом, вам нужно назначить окончательные значения на этапе 2.

Документация немного неясна, но кажется, что вы должны продолжать использовать типичное для Objective C соглашение о вызове инициализации суперкласса первым.

Я предполагаю, что это Objective C, и я не знаком с этим языком, но, говоря о работе объектно-ориентированных языков программирования в целом, конструкторы / инициализаторы являются и должны вызываться из наименее производного класса в наиболее производный класс и деструкторы. в обратном порядке.

Подумайте об этом так: если базовый класс - это торт, а ваш производный класс добавляет глазурь, вы не можете поставить глазурь на место до того, как торт будет построен.

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

В C++ и C# язык выделяет объект, инициализирует наименее производный компонент, указывает виртуальные функции на первый производный класс, а затем создает его и т. Д. Классы не вызывают инициализаторы суперкласса.

Я знаю, что не ответил на ваш вопрос, но, возможно, это поможет вам выяснить ответ. Сначала вызов super.init(), если вы собираетесь вызывать super.init(), может показаться правильным решением.

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

Другие вопросы по тегам