1
votes

So I have a class with a designated initializer that takes values for every stored property. All my stored properties also have a default values, so I assume this class get a default init.

In my designated init, I call super.init()

The problem is, if I call it at the end of my init, it loads all properties to default values, but if I call it at the start it works as I expect.

The book says:

Safety check 1 A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.

As mentioned above, the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all its own properties are initialized before it hands off up the chain.

So I am not sure if things have changed or I am doing something wrong?

Code:

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
Are the properties defined by this class or are they inherited from the super class? - Paulw11
They are defined by this class, so based on Apple's doc, I should be initializing before calling super. - Vipul Patil
Is your initialiser marked as convenience or is it the designated initialiser? - Paulw11
Code added for clarity. Should answer your question. - Vipul Patil
Why do you set your values to defaults and have a designated initialiser that sets defaults? - Paulw11

2 Answers

1
votes

The correct solution is to call super.init before you assign the final values, as you have observed. Safety check 1, as you said, requires that all of the properties introduced by the subclass are initialised before delegating up - this is taken care of by your default assignments.

Safety check 1 is applied during phase 1 of the initialisation process.

Phase 2 of the initialisation process then occurs -

Phase 2

Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on. Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.

So you need to assign the final values during phase 2.

The documentation is a little unclear, but it seems that you should continue to use the typical convention from Objective C of calling the superclass init first.

-4
votes

I assume this is Objective C, and I am not familiar with that language, but speaking of the operation of object oriented programming languages in general, constructors/initializers are and must be called from the least derived class to the most derived class, and destructors in the opposite order.

Think of it this way, if the base class is the cake, and your derived class adds icing, you can't put the icing in place before the cake is constructed.

As for the meaning of the statement from the book, at the time your initialize is called, if virtual functions are already pointing at your derived class' functionality, then your class has to be initialized before you chance having virtual functions called.

In C++ and C#, the language allocates the object, initializes the least derived component, points virtual functions to the first derived class and then constructs it, and so on. Classes don't call superclass initializers.

I know I did not answer your question, but perhaps this will help you figure out the answer. Calling super.init() first, if you are going to call super.init(), would seem to be the proper course of action.

Perhaps this is the answer: if virtual functions do point to your overrides, which they must, but you have to call super.init(), then you would need to initialize your data members in case a virtual function is called, call super.init() to initialize the inner class, and then continue with your initialization process. It all sounds very unsafe to me, but I see no other way it could work.