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.