Skip to content

Initialization ​

Initialization prepares an instance of a class, structure, or enumeration for use by setting initial values for stored properties and performing any necessary setup.

In Swift, initialization ensures that every stored property has a value before the instance is ready. Initializers are special methods called to create new instances. They don't return a value; their job is to fully initialize the instance.

Classes can also have deinitializers for cleanup before deallocation (see Deinitialization for details).

Setting Initial Values for Stored Properties ​

All stored properties in classes and structures must receive an initial value during creation. You can't leave them uninitialized.

Set values either in an initializer or as a default in the property declaration. Default values or initializer assignments set properties directly, bypassing observers.

Initializers ​

Initializers create new instances. A basic one looks like this:

swift
init() {
    // setup code
}

Example: A LengthInMeters structure for storing lengths, with a default of 0:

swift
struct LengthInMeters {
    var value: Double
    init() {
        value = 0.0
    }
}
let zeroLength = LengthInMeters()
print("Default length: \(zeroLength.value) meters")
// Prints "Default length: 0.0 meters"

Default Property Values ​

Assign defaults directly in declarations for simpler code:

swift
struct LengthInMeters {
    var value = 0.0
}

Defaults tie initialization closely to declarations, enabling type inference and easier use of inherited initializers.

Customizing Initialization ​

Customize with parameters, optional properties, or constants during init.

Initialization Parameters ​

Parameters let you pass values:

swift
struct LengthInFeet {
    var valueInFeet: Double
    init(fromMeters meters: Double) {
        valueInFeet = meters * 3.28084
    }
    init(fromInches inches: Double) {
        valueInFeet = inches / 12.0
    }
}
let oneMeterInFeet = LengthInFeet(fromMeters: 1.0)
// oneMeterInFeet.valueInFeet ≈ 3.28084
let twelveInches = LengthInFeet(fromInches: 12.0)
// twelveInches.valueInFeet = 1.0

Parameter Names and Argument Labels ​

Initializers use argument labels by default. Use underscores to omit:

swift
struct LengthInFeet {
    var valueInFeet: Double
    init(fromMeters meters: Double) {
        valueInFeet = meters * 3.28084
    }
    init(_ feet: Double) {
        valueInFeet = feet
    }
}
let directFeet = LengthInFeet(5.0)  // No label needed

Optional Property Types ​

Optionals auto-init to nil:

swift
class MeasurementTool {
    var name: String
    var accuracy: Double?
    init(name: String) {
        self.name = name
    }
    func describe() {
        print(name)
    }
}
let ruler = MeasurementTool(name: "Ruler")
ruler.describe()  // Prints "Ruler"
ruler.accuracy = 0.1

Assigning Constant Properties During Initialization ​

Constants can be set during init but not after:

swift
class MeasurementTool {
    let name: String
    var accuracy: Double?
    init(name: String) {
        self.name = name
    }
    func describe() {
        print(name)
    }
}

Default Initializers ​

Structures or classes with defaults for all properties get a free default init:

swift
class InventoryItem {
    var id: String?
    var count = 1
    var inStock = true
}
let item = InventoryItem()  // Uses default values

Memberwise Initializers for Structures ​

Structures get auto memberwise init if no custom ones:

swift
struct Dimensions {
    var length = 0.0, width = 0.0
}
let square = Dimensions(length: 2.0, width: 2.0)
let defaultDim = Dimensions()  // 0.0, 0.0

Initializer Delegation for Value Types ​

Value types delegate to other inits with self.init:

swift
struct Box {
    var position = Point()
    var size = Dimensions()
    init() {}
    init(position: Point, size: Dimensions) {
        self.position = position
        self.size = size
    }
    init(center: Point, size: Dimensions) {
        let posX = center.x - (size.length / 2)
        let posY = center.y - (size.width / 2)
        self.init(position: Point(x: posX, y: posY), size: size)
    }
}

Custom inits block defaults unless in extensions.

Class Inheritance and Initialization ​

Classes must init inherited properties too. Use designated (primary) and convenience (secondary) inits.

Designated and Convenience Initializers ​

Designated fully init; convenience delegate to designated.

Syntax:

swift
init(parameters) { ... }  // Designated
convenience init(parameters) { ... }  // Convenience

Rules: Designated delegate up; convenience across; end at designated.

Two-Phase Initialization ​

Phase 1: Assign all properties bottom-up.

Phase 2: Customize top-down.

Safety checks ensure proper order.

Initializer Inheritance and Overriding ​

Subclasses don't auto-inherit inits. Override with 'override':

swift
class Container {
    var capacity = 0
}
class Bottle: Container {
    override init() {
        super.init()
        capacity = 500
    }
}

Omit super.init if no phase 2 customization and superclass has zero-arg init.

Automatic Initializer Inheritance ​

Inherit if no designated or all superclass designated implemented.

In Action ​

Base: Item with name.

swift
class Item {
    var name: String
    init(name: String) { self.name = name }
    convenience init() { self.init(name: "[Unknown]") }
}

Subclass: StockItem adds quantity.

swift
class StockItem: Item {
    var quantity: Int
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    override convenience init(name: String) {
        self.init(name: name, quantity: 1)
    }
}

Further subclass: ListItem adds checked flag.

swift
class ListItem: StockItem {
    var checked = false
    var info: String {
        "\(quantity) x \(name)" + (checked ? " ✓" : " ✗")
    }
}

Inherits all inits.

Failable Initializers ​

Use init? for possible failure:

swift
struct Tool {
    let type: String
    init?(type: String) {
        if type.isEmpty { return nil }
        self.type = type
    }
}

Fail with return nil.

For enums:

swift
enum Unit: Character {
    case meter = "M", foot = "F"
}
let unit = Unit(rawValue: "M")  // .meter?

Propagation: Failure bubbles up.

Overriding: Can make nonfailable.

init! for implicitly unwrapped.

Required Initializers ​

Mark with 'required' for subclasses to implement:

swift
class BaseTool {
    required init() { ... }
}
class SubTool: BaseTool {
    required init() { ... }
}

Setting Default Property Value with Closure ​

Use closures for complex defaults:

swift
struct Grid {
    let colors: [Bool] = {
        var temp: [Bool] = []
        var dark = false
        for _ in 1...4 {
            for _ in 1...4 {
                temp.append(dark)
                dark = !dark
            }
            dark = !dark
        }
        return temp
    }()
    func isDark(atRow row: Int, col: Int) -> Bool {
        colors[(row * 4) + col]
    }
}

Released under the MIT License.