Swift Classes โ Initializers and the super.init() Rule ๐๏ธ
Class initializers in Swift come with one golden rule that catches everyone out the first time. Let's talk about what it is, why it exists, and how to stop forgetting it. Okay so we need to talk about initializers again. I know, I know โ we covered them in the structs chapter. But classes have a twi

Class initializers in Swift come with one golden rule that catches everyone out the first time. Let's talk about what it is, why it exists, and how to stop forgetting it. Okay so we need to talk about initializers again. I know, I know โ we covered them in the structs chapter. But classes have a twist that trips people up the first time they hit it, and it's worth slowing down on before you run into it at 11pm debugging something that seems like it should be obvious. Here's the short version of what we're going to learn today: When a child class has its own initializer, it must call the parent's initializer โ and it has to do it after setting up its own stuff first. That's it. That's the rule. But let's actually understand why, because "just do it" is a terrible way to remember something. ๐ฅ Let's build a ninja academy system. Every person in the ninja world has a chakraType โ whether they use fire, wind, water, earth, or lightning chakra. That's a property that belongs to everyone, so it lives in the parent class: class NinjaAcademy { let chakraType: String init(chakraType: String) { self.chakraType = chakraType } } Simple enough. Now let's say we want a StudentNinja that inherits from NinjaAcademy but also has a rank โ like Genin, Chunin, or Jonin: class StudentNinja: NinjaAcademy { let rank: String init(rank: String) { self.rank = rank } } This looks reasonable. But Swift will refuse to build it. And the error message will say something like: "Super.init isn't called on all paths before returning from initializer." Here's the problem. NinjaAcademy has a property called chakraType. It's required โ there's no default value, and Swift's golden rule for initializers is every property must have a value by the time initialization is done. When StudentNinja is created, it inherits chakraType from NinjaAcademy. But who sets it? StudentNinja's initializer doesn't mention it. And if nobody sets it, chakraType ends up without a value โ which Swift will not allow. The solution is to accept chakraType in StudentNinja's initializer too, and then pass it up to NinjaAcademy using super.init(): class StudentNinja: NinjaAcademy { let rank: String init(chakraType: String, rank: String) { self.rank = rank super.init(chakraType: chakraType) } } Now it works. Let's break down what's happening on those two critical lines. Notice the order: self.rank = rank // 1. Set your own properties first super.init(chakraType: chakraType) // 2. Then call the parent's initializer This order is not optional. Swift enforces it. If you try to call super.init() before setting self.rank, Swift will refuse: // โ This won't work โ wrong order init(chakraType: String, rank: String) { super.init(chakraType: chakraType) self.rank = rank // too late โ super.init already ran } The reason is safety. Swift wants to make sure the current class's own properties are fully set up before it hands control to the parent class. If something went wrong during super.init(), you'd at least know your own class's properties were in a valid state. Think of it like building a house. You have to finish your own floor before you can ask the architect to come check the whole building. The architect (super.init) needs to know the floor they're standing on is solid. With the initializers in place, you can now create a StudentNinja like this: let sakura = StudentNinja(chakraType: "Fire", rank: "Genin") print(sakura.chakraType) // "Fire" โ inherited from NinjaAcademy print(sakura.rank) // "Genin" โ defined in StudentNinja Both properties are accessible, both are set correctly. sakura is a StudentNinja, but she also has everything NinjaAcademy defined because that's what inheritance gives you. Here's the good news: if your subclass doesn't add any new properties that need setting, you don't need to write an initializer at all. Swift will just inherit the parent's automatically: class EliteNinja: NinjaAcademy { func specialMove() { print("Using \(chakraType) chakra for a special attack!") } } let kakashi = EliteNinja(chakraType: "Lightning") kakashi.specialMove() // "Using Lightning chakra for a special attack!" EliteNinja adds a method but no new properties โ so it inherits NinjaAcademy's initializer for free and you don't have to write anything. The super.init() requirement only kicks in when your subclass has its own new properties that need setting. super Is Not Just for Initializers While we're here โ super isn't limited to init. You can use it to call any method from the parent class, which is useful when you're overriding a method but still want to run the parent's version too: class Hokage: NinjaAcademy { let title: String init(chakraType: String, title: String) { self.title = title super.init(chakraType: chakraType) } override func someMethod() { super.someMethod() // runs the parent's version first print("And then does something extra.") } } Same pattern: super gives you access to the parent, whether you're in an initializer or a regular method. The rule that catches everyone: when your child class has its own initializer, set your own properties first, then call super.init(). Get that order right and everything works. Get it backwards and Swift will stop you immediately. It feels pedantic until you understand why โ Swift is making sure every single property has a value before initialization completes, no matter how deep the inheritance chain goes. That's not pedantry, that's safety. ๐ธ This article was written by me; AI was used to improve grammar and readability.
Key Takeaways
- โขClass initializers in Swift come with one golden rule that catches everyone out the first time
- โขThis story was reported by Dev.to, covering developments in the dev space.
- โขAI advancements continue to reshape industries โ read the full article on Dev.to for complete coverage.
๐ Continue reading the full article:
Read Full Article on Dev.to โShare this article



