Error in Swift class: Property not initialized at super.init call

PropertiesCompiler ErrorsSwift

Properties Problem Overview


I have two classes, Shape and Square

class Shape {
    var numberOfSides = 0
    var name: String
    init(name:String) {
        self.name = name
    }
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

class Square: Shape {
    var sideLength: Double

    init(sideLength:Double, name:String) {
        super.init(name:name) // Error here
        self.sideLength = sideLength
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}

With the implementation above I get the error:

property 'self.sideLength' not initialized at super.init call
    super.init(name:name)

Why do I have to set self.sideLength before calling super.init?

Properties Solutions


Solution 1 - Properties

Quote from The Swift Programming Language, which answers your question:

> “Swift’s compiler performs four helpful safety-checks to make sure > that two-phase initialization is completed without error:” > > 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.” > > Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. > https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11

Solution 2 - Properties

Swift has a very clear, specific sequence of operations that are done in initializers. Let's start with some basic examples and work our way up to a general case.

Let's take an object A. We'll define it as follows.

class A {
    var x: Int
    init(x: Int) {
        self.x = x
    }
}

Notice that A does not have a superclass, so it cannot call a super.init() function as it does not exist.

OK, so now let's subclass A with a new class named B.

class B: A {
    var y: Int
    init(x: Int, y: Int) {
        self.y = y
        super.init(x: x)
    }
}

This is a departure from Objective-C where [super init] would typically be called first before anything else. Not so in Swift. You are responsible for ensuring that your instance variables are in a consistent state before you do anything else, including calling methods (which includes your superclass' initializer).

Solution 3 - Properties

From the docs

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


Why do we need a safety check like this?

To answer this lets go though the initialization process in swift.

> Two-Phase Initialization > > Class initialization in Swift is a two-phase process. In the first > phase, each stored property is assigned an initial value by the class > that introduced it. Once the initial state for every stored property > has been determined, the second phase begins, and each class is given > the opportunity to customize its stored properties further before the > new instance is considered ready for use. > > The use of a two-phase initialization process makes initialization > safe, while still giving complete flexibility to each class in a class > hierarchy. Two-phase initialization prevents property values from > being accessed before they are initialized, and prevents property > values from being set to a different value by another initializer > unexpectedly.

So, to make sure the two step initialization process is done as defined above, there are four safety checks, one of them is,

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

Now, the two phase initialization never talks about order, but this safety check, introduces super.init to be ordered, after the initialization of all the properties.

Safety check 1 might seem irrelevant as, Two-phase initialization prevents property values from being accessed before they are initialized can be satisfied, without this safety check 1.

Like in this sample

class Shape {
    var name: String
    var sides : Int
    init(sides:Int, named: String) {
        self.sides = sides
        self.name = named
    }
}

class Triangle: Shape {
    var hypotenuse: Int
    init(hypotenuse:Int) {
        super.init(sides: 3, named: "Triangle") 
        self.hypotenuse = hypotenuse
    }
}

Triangle.init has initialized, every property before being used. So Safety check 1 seems irrelevant,

But then there could be another scenario, a little bit complex,

class Shape {
    var name: String
    var sides : Int
    init(sides:Int, named: String) {
        self.sides = sides
        self.name = named
        printShapeDescription()
    }
    func printShapeDescription() {
        print("Shape Name :\(self.name)")
        print("Sides :\(self.sides)")
    }
}

class Triangle: Shape {
    var hypotenuse: Int
    init(hypotenuse:Int) {
        self.hypotenuse = hypotenuse
        super.init(sides: 3, named: "Triangle")
    }
    
    override func printShapeDescription() {
        super.printShapeDescription()
        print("Hypotenuse :\(self.hypotenuse)")
    }
}

let triangle = Triangle(hypotenuse: 12)

Output :

Shape Name :Triangle
Sides :3
Hypotenuse :12

Here if we had called the super.init before setting the hypotenuse, the super.init call would then have called the printShapeDescription() and since that has been overridden it would first fallback to Triangle class implementation of printShapeDescription(). The printShapeDescription() of Triangle class access the hypotenuse a non optional property that still has not been initialised. And this is not allowed as Two-phase initialization prevents property values from being accessed before they are initialized

So make sure the Two phase initialization is done as defined, there needs to be a specific order of calling super.init, and that is, after initializing all the properties introduced by self class, thus we need a Safety check 1

Solution 4 - Properties

The "super.init()" should be called after you initialize all your instance variables.

In Apple's "Intermediate Swift" video (you can find it in Apple Developer video resource page https://developer.apple.com/videos/wwdc/2014/), at about 28:40, it is explicit said that all initializers in super class must be called AFTER you initialize your instance variables.

In Objective-C, it was the reverse. In Swift, since all properties need to be initialized before it's used, we need to initialize properties first. This is meant to prevent a call to overrided function from super class's "init()" method, without initializing properties first.

So the implementation of "Square" should be:

class Square: Shape {
    var sideLength: Double

    init(sideLength:Double, name:String) {
        self.sideLength = sideLength
        numberOfSides = 4
        super.init(name:name) // Correct position for "super.init()"
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}

Solution 5 - Properties

Sorry for ugly formatting. Just put a question character after declaration and everything will be ok. A question tells the compiler that the value is optional.

class Square: Shape {
    var sideLength: Double?   // <=== like this ..

    init(sideLength:Double, name:String) {
        super.init(name:name) // Error here
        self.sideLength = sideLength
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}

Edit1:

There is a better way to skip this error. According to jmaschad's comment there is no reason to use optional in your case cause optionals are not comfortable in use and You always have to check if optional is not nil before accessing it. So all you have to do is to initialize member after declaration:

class Square: Shape {
    var sideLength: Double=Double()   

    init(sideLength:Double, name:String) {
        super.init(name:name)
        self.sideLength = sideLength
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}

Edit2:

After two minuses got on this answer I found even better way. If you want class member to be initialized in your constructor you must assign initial value to it inside contructor and before super.init() call. Like this:

class Square: Shape {
    var sideLength: Double  

    init(sideLength:Double, name:String) {
        self.sideLength = sideLength   // <= before super.init call..
        super.init(name:name)
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}

Good luck in learning Swift.

Solution 6 - Properties

swift enforces you to initialise every member var before it is ever/might ever be used. Since it can't be sure what happens when it is supers turn, it errors out: better safe than sorry

Solution 7 - Properties

Edward,

You can modify the code in your example like this:

var playerShip:PlayerShip!
var deltaPoint = CGPointZero

init(size: CGSize)
{
    super.init(size: size)
    playerLayerNode.addChild(playerShip)        
}

This is using an implicitly unwrapped optional.

In documentation we can read:

> "As with optionals, if you don’t provide an initial value when you > declare an implicitly unwrapped optional variable or property, it’s > value automatically defaults to nil."

Solution 8 - Properties

Swift will not allow you to initialise super class with out initialising the properties, reverse of Obj C. So you have to initialise all properties before calling "super.init".

Please go to http://blog.scottlogic.com/2014/11/20/swift-initialisation.html. It gives a nice explanation to your problem.

Solution 9 - Properties

Add nil to the end of the declaration.


// Must be nil or swift complains
var someProtocol:SomeProtocol? = nil

// Init the view
override init(frame: CGRect)
    super.init(frame: frame)
    ...

This worked for my case, but may not work for yours

Solution 10 - Properties

its should be this:

init(sideLength:Double, name:String) {
    self.sideLength = sideLength
    super.init(name:name)
    numberOfSides = 4
}

look at this link: https://swiftgg.gitbook.io/swift/swift-jiao-cheng/14_initialization#two-phase-initialization

Solution 11 - Properties

You are just initing in the wrong order.

     class Shape2 {
        var numberOfSides = 0
        var name: String
        init(name:String) {
            self.name = name
        }
        func simpleDescription() -> String {
            return "A shape with \(numberOfSides) sides."
        }
    }
    
    class Square2: Shape2 {
        var sideLength: Double
        
        init(sideLength:Double, name:String) {
           
            self.sideLength = sideLength
            super.init(name:name) // It should be behind "self.sideLength = sideLength"
            numberOfSides = 4
        }
        func area () -> Double {
            return sideLength * sideLength
        }
    }

Solution 12 - Properties

@Janos if you make the property optional, you don't have to initialise it in init. –

This worked for me.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJuJoDiView Question on Stackoverflow
Solution 1 - PropertiesRubenView Answer on Stackoverflow
Solution 2 - PropertiesHitendra SolankiView Answer on Stackoverflow
Solution 3 - PropertiesBangOperatorView Answer on Stackoverflow
Solution 4 - PropertiesShuyangView Answer on Stackoverflow
Solution 5 - Propertiesfnc12View Answer on Stackoverflow
Solution 6 - PropertiesDaij-DjanView Answer on Stackoverflow
Solution 7 - PropertiesPavel GubarevView Answer on Stackoverflow
Solution 8 - Propertiesjishnu balaView Answer on Stackoverflow
Solution 9 - PropertiesMichaelView Answer on Stackoverflow
Solution 10 - Properties1215cccView Answer on Stackoverflow
Solution 11 - PropertiesylgwhyhView Answer on Stackoverflow
Solution 12 - PropertiesgoroView Answer on Stackoverflow