Working with Initializers
1. Defining Designated Initializers
| Property | Description | Example |
|---|---|---|
| Designated Initializer | Primary initializer for a class that fully configures all properties and calls a superclass initializer | |
| Required Properties | All stored properties must be assigned a value before the initializer ends | |
| Superclass Call | Must call super.init() in subclasses before assigning properties |
|
Example: Designated Initializer with Default Values
class Rectangle {
var width: Double
var height: Double
init(width: Double = 1.0, height: Double = 1.0) {
self.width = width
self.height = height
}
}
2. Defining Convenience Initializers
| Property | Description | Notes |
|---|---|---|
| convenience init() | Defines a convenience initializer for a class | Must call a designated initializer using self.init() |
| parameter | Parameters for the initializer | Can include default values and optionals |
Example: Defining a Convenience Initializer
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
convenience init(name: String) {
self.init(name: name, age: 0)
}
}
Note: Convenience initializers must call a designated initializer using
self.init().3. Understanding Initialization Phases
| Phase | Description | Key Characteristics |
|---|---|---|
| 1. Memberwise Initialization | Swift automatically provides a memberwise initializer for structs and classes with no custom initializers. | Only available for structs with no stored properties. For classes, it's not provided unless custom initializers are added. |
| 2. Designated Initializer | Primary initializer for a class that fully initializes all properties and calls the superclass initializer. | Every class must have at least one designated initializer. It can be overridden in subclasses. |
| 3. Convenience Initializer | Secondary initializer that delegates to a designated initializer in the same class. | Can only delegate to another initializer in the same class. Must call a designated initializer before finishing. |
| 4. Failable Initializer | Initializers that can fail to create an instance, returning an optional. | Declared with init?. Can return nil if initialization fails. |
| 5. Required Initializer | Initializers marked with required, enforced in subclasses. |
Must be implemented by any subclass that inherits from the class. |
Example: Initialization Phases in a Class
class Vehicle {
var make: String
var model: String
var year: Int
// Designated initializer
init(make: String, model: String, year: Int) {
self.make = make
self.model = model
self.year = year
}
// Convenience initializer
convenience init(make: String, model: String) {
self.init(make: make, model: model, year: 2024)
}
// Failable initializer
init?(make: String, model: String, year: Int?) {
guard let year = year else { return nil }
self.make = make
self.model = model
self.year = year
}
}
class Car: Vehicle {
var doors: Int
// Required initializer (must be implemented)
required init(make: String, model: String, year: Int) {
self.doors = 4
super.init(make: make, model: model, year: year)
}
}
4. Using Required Initializers
| Property | Description | Usage |
|---|---|---|
| required | Marks a initializer as required for all subclasses | Used to enforce that subclasses must implement this initializer |
Example: Required Initializer in a Class
class Vehicle {
var wheels: Int
required init(wheels: Int) {
self.wheels = wheels
}
}
class Car: Vehicle {
var doors: Int
required init(wheels: Int) {
self.doors = 4
super.init(wheels: wheels)
}
}
Note: The
required keyword ensures that subclasses implement the initializer, even if they have their own custom logic.
5. Creating Failable Initializers
Failable initializers in Swift are used when initialization might fail under certain conditions. They are declared using the init? syntax and return an optional type.
| Property | Description | Example |
|---|---|---|
| init? | Declares a failable initializer | init?(String) -> MyType? |
| return value | Optional type (MyType?) | return MyType(value) |
Example: Failable initializer for a User model
struct User {
let name: String
let age: Int
init?(name: String, age: Int) {
guard !name.isEmpty else { return nil }
guard age >= 0 else { return nil }
self.name = name
self.age = age
}
}
Note: If any of the conditions in the initializer's body fail, the initializer returns
nil.Key Points
- Failable initializers are declared with
init? - They return an optional of the type being initialized
- Use
guardorif letto validate input before initializing - If validation fails, return
nilto indicate failure
6. Using Default Initializers
| Property | Description | Usage |
|---|---|---|
| init() | Default initializer with no parameters | Creates an instance with default values |
| init?(coder: NSCoder) | Initializer for Interface Builder and storyboard | Used when loading views from nib or storyboard |
Example: Default Initializer
class Person {
var name: String = "Unknown"
var age: Int = 0
init() {
// Default values are assigned
}
}
let person = Person()
print(person.name) // "Unknown"
Example: NSCoder Initializer
class CustomView: UIView {
required init?(coder: NSCoder) {
super.init(coder: coder)
// Custom setup when loaded from storyboard
}
}
7. Implementing Memberwise Initializers
| Property | Value | Description |
|---|---|---|
| memberwise initializer | init(name: String, age: Int) |
Automatically generated initializer for all stored properties |
| customization | init(name: String, age: Int) { ... } |
Override to provide custom initialization logic |
Example: Memberwise Initializer
struct Person {
var name: String
var age: Int
}
let person = Person(name: "Alex", age: 30)
print(person.name) // Alex
Example: Custom Memberwise Logic
struct Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let person = Person(name: "Alex", age: 30)
print(person.name) // Alex
8. Using Closure-Based Initialization
| Property | Description | Usage |
|---|---|---|
| closure | A block of code that can be executed later | Used to initialize properties with dynamic values |
Example: Closure-Based Initialization
class Person {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
init(name: String, ageInitializer: () -> Int) {
self.name = name
self.age = ageInitializer()
}
}
let person1 = Person(name: "Alice", age: 30)
let person2 = Person(name: "Bob", ageInitializer: { return 25 })
Note: Closure-based initialization allows for dynamic property values at runtime.
9. Understanding Initializer Inheritance
| Concept | Description | Details |
|---|---|---|
| Initializer Inheritance | Subclasses inherit initializers from their superclass | Swift automatically provides a default initializer if no custom initializers are defined in the subclass |
| Convenience Initializers | Can be inherited but not overridden | When a subclass defines its own convenience initializers, it does not inherit the superclass’s convenience initializers |
| Required Initializers | Must be implemented in subclasses | If a superclass has required initializers, subclasses must implement them or mark themselves as non-entrant |
Example: Inheriting Initializers
class Vehicle {
var wheels: Int
init(wheels: Int) {
self.wheels = wheels
}
}
class Car: Vehicle {
var doors: Int
init(doors: Int) {
self.doors = doors
super.init(wheels: 4)
}
}
Note: If a subclass does not define any initializers, it will inherit all initializers from its superclass.
10. Implementing Deinitialization
Deinitializers are used to clean up resources before an instance of a class is deallocated. They are called automatically just before deallocation occurs.
| Feature | Description | Notes |
|---|---|---|
| deinit | deinit keyword is used to define a deinitializer |
Cannot have parameters or return type |
Example: Basic Deinitializer
class MyClass {
var resource: String = "Some Resource"
deinit {
print("Deinitializing MyClass")
// Clean up resources here
}
}
var instance: MyClass? = MyClass()
instance = nil // Triggers deinit
Note: Deinitializers are not called immediately when a variable is set to
nil. They are called during the deallocation process, which happens at an unspecified time.