252

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?

jscs
  • 63,694
  • 13
  • 151
  • 195
JuJoDi
  • 14,627
  • 23
  • 80
  • 126

12 Answers12

189

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

Ruben
  • 5,043
  • 2
  • 25
  • 49
  • 53
    Now that's a staggering change compared to C++, C# or Java. – Maciej Jastrzebski Jun 03 '14 at 18:43
  • 14
    @MDJ Sure thing. I honestly don't see the added value of it either. – Ruben Jun 03 '14 at 18:48
  • 22
    Actually there seems to be one. Say in C#, superclass constructor should not call any overridable (virtual) methods, because nobody knows how they would react with not fully initialized subclass. In Swift is ok, as subclass-extra state is fine, when superclass constructor is running. Moreover, in Swift all but final methods are overridable. – Maciej Jastrzebski Jun 03 '14 at 18:55
  • 1
    doesn't it introduce problem with properties which can only be initialised in a later stage of the lifecycle (like in a viewDidLoad method, etc?). Actually, see this: http://stackoverflow.com/questions/24107938/lazy-property-initialization-in-swift – Janos Jul 14 '14 at 07:26
  • 21
    I'm particularly finding it annoying because it means, if I want to make a UIView subclass which creates its own subviews, I have to initialise those subviews without frames to begin with and add the frames later since I can't refer to the view's bounds until AFTER calling super.init. – Ash Oct 19 '14 at 11:46
  • 6
    @Janos if you make the property optional, you don't have to initialise it in `init`. – JeremyP May 12 '15 at 15:41
123

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

Dylan Hand
  • 1,190
  • 2
  • 14
  • 21
Hitendra Solanki
  • 4,871
  • 2
  • 22
  • 29
  • 3
    this is extremely helpful, a clear example. thank you! – FullMetalFist May 23 '17 at 18:08
  • What if I need the value to calculate y, for example: init(y: Int) { self.y = y * self.x super.init() } – 6rod9 Dec 12 '17 at 18:59
  • 1
    use something like, init(y: Int, x: Int = 0) { self.y = y * x; self.x = x; super.init(x: x) } , also you cannot directly call empty constructor for the super class with reference to above example, because super class names A does not have empty constructor – Hitendra Solanki Dec 13 '17 at 04:14
  • But if I follow this, I get this error: `'self' used before 'super.init' call` :( – huskygrad Mar 31 '22 at 07:35
47

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

BangOperator
  • 4,377
  • 2
  • 24
  • 38
  • 1
    Great explanation, the *why* should definitely added to the top answer. – Guy Daher May 02 '17 at 13:24
  • So you're basically saying, because the superclass's `init` *may* call a (overriden) function...in which that function access the subclasses property, then to avoid not having values set, the call to `super` must happen after all values are set. OK makes sense. Wonder how Objective-C did it then and why you had to call `super` first? – mfaani Aug 27 '17 at 17:59
  • Essentially what you're pointing out to is *similar* to: placing `printShapeDescription()` **before** `self.sides = sides; self.name = named;` which would generate this error: `use of 'self' in method call 'printShapeDescription' before all stored properties are initialized`. The error of the OP is given to reduce 'possibility' of runtime error. – mfaani Aug 27 '17 at 18:12
  • I specifically used the word 'possibility', because if `printShapeDescription` was a function that didn't refer to `self` ie it be something like `print("nothing") then there would have been no issues. (Yet even for that the compiler would throw an error, because it's not *super* smart) – mfaani Aug 27 '17 at 18:16
  • Well objc just wasn’t safe. Swift is type safe so objects that aren’t optional really need to be nonnil! – Daij-Djan Sep 01 '17 at 15:15
  • @Honey, "Wonder how Objective-C did it then and why you had to call super first?" Swift introduced lots of new stuff, one of them was Two phase initialization and, it was not necessary in Obj-C to call super.init first. – BangOperator Sep 09 '17 at 19:13
  • @BangOperator and since it is wan't mandatory, you could have still ran into some runtime issues right? – mfaani Sep 10 '17 at 03:17
  • @Honey no, not in obj c. In obj c even without explicit initialisation, primitive properties are set to default values and property objects are set to nil. – BangOperator Sep 10 '17 at 04:28
38

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
    }
}
Shuyang
  • 520
  • 4
  • 6
16

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.

fnc12
  • 2,241
  • 1
  • 21
  • 27
  • Just switch `super.init(name:name)` and `self.sideLength = sideLength`. Declaring `sideLength` as optional is misguiding and introduces additional hassle later on when you have to force unwrap it. – Johannes Luong Jun 06 '14 at 12:48
  • Yeah, this is an option. Thanks – fnc12 Jun 09 '14 at 13:51
  • You actually can just have `var sideLength: Double`, no need to assign it an initial value – Jarsen Aug 19 '14 at 21:41
  • What if I really have an optional constant. What do I do with it? Do I have to initialize in the constructor? I don't see why you have to do it, but the compiler is complaining in Swift 1.2 – Van Du Tran Apr 15 '15 at 13:49
  • @VanDuTran what is the purpose of having an optional constant? Why don't you use non-optional constant instead? – fnc12 Apr 15 '15 at 15:16
  • @fnc12 let's say we can apply a texture to the Square. But not all Square must have a texture, so it's optional. And for the sake of example, let's suppose it's a constant because once you paint it with a texture, you can't change it. There are many possible use case for constant optional, I'm just wondering how you would handle their initialization. Swift 1.2 has changed stuffs.. – Van Du Tran Apr 15 '15 at 16:05
  • @VanDuTran I Ok, now I see. The thing you are talking about is an optional (or just variable) assigned only once. You can create a generic class and overload operator= and make assignment for the first time and throw exceptions next time operator= is called. But it is all runtime stuff, not compile-time. – fnc12 Apr 16 '15 at 11:26
  • The question mark thing seems like the way to go. It matches my ?!?!?! tattoo that I got on my face in honor of Swift – CommaToast Jan 23 '16 at 18:38
  • 1
    Perfect ! all 3 solutions worked "?", "String()", but the issue for me was I had not 'assigned' one of the property, and when I did that it worked ! Thanks mate – Naishta May 10 '16 at 21:57
  • downvoted because it starts misleading and causes confusion by not answering the question - having to read through 2 updates to follow the learning experience of the author of the answer is not a good quality answer :) sorry – phlebotinum Jun 19 '16 at 12:21
9

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

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • 1
    This doesn't make sense IMO because the parent class should have no visibility into the properties declared in it's children! – Andy Hin Sep 23 '15 at 01:32
  • 1
    It doesn't but you may override stuff and begin using self 'before super made it' – Daij-Djan Sep 23 '15 at 07:32
  • Can you see [here](https://stackoverflow.com/questions/24021093/error-in-swift-class-property-not-initialized-at-super-init-call/40161029#comment78774263_40161029) and comments that follow it? I think I'm saying exactly what you're saying ie we're both saying the compiler wants to be safe rather than sorry, my only question is, so how did objective-c solve this problem? Or it didn't? If it didn't then why does it still require you to write `super.init` in the first line? – mfaani Aug 27 '17 at 20:14
6

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

zizoujab
  • 7,603
  • 8
  • 41
  • 72
  • I think this is the cleanest option. In my very first Swift attempt, I had a member variable of type AVCaptureDevice, which cannot be instantiated directly, so init() code was required. However, ViewController requires multiple initializers, and you can't call a common initialization method from init(), so this answer seems to be the only option that avoids copy/pasting duplicate code in every initializer. – sunetos Jun 21 '14 at 19:07
  • How can this work? You pass `playerShip` to `addChild` but you never initialize `playerShip`. – HangarRash Jul 13 '23 at 00:33
6

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.

jishnu bala
  • 665
  • 8
  • 17
5

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

Michael
  • 9,639
  • 3
  • 64
  • 69
4

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

1215ccc
  • 41
  • 5
0

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
        }
    }
ylgwhyh
  • 1,588
  • 18
  • 21
-1

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

This worked for me.

gaurav
  • 75
  • 1
  • 3