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:
init() {
// setup code
}Example: A LengthInMeters structure for storing lengths, with a default of 0:
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:
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:
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.0Parameter Names and Argument Labels
Initializers use argument labels by default. Use underscores to omit:
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 neededOptional Property Types
Optionals auto-init to nil:
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.1Assigning Constant Properties During Initialization
Constants can be set during init but not after:
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:
class InventoryItem {
var id: String?
var count = 1
var inStock = true
}
let item = InventoryItem() // Uses default valuesMemberwise Initializers for Structures
Structures get auto memberwise init if no custom ones:
struct Dimensions {
var length = 0.0, width = 0.0
}
let square = Dimensions(length: 2.0, width: 2.0)
let defaultDim = Dimensions() // 0.0, 0.0Initializer Delegation for Value Types
Value types delegate to other inits with self.init:
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:
init(parameters) { ... } // Designated
convenience init(parameters) { ... } // ConvenienceRules: 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':
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.
class Item {
var name: String
init(name: String) { self.name = name }
convenience init() { self.init(name: "[Unknown]") }
}Subclass: StockItem adds quantity.
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.
class ListItem: StockItem {
var checked = false
var info: String {
"\(quantity) x \(name)" + (checked ? " ✓" : " ✗")
}
}Inherits all inits.
Failable Initializers
Use init? for possible failure:
struct Tool {
let type: String
init?(type: String) {
if type.isEmpty { return nil }
self.type = type
}
}Fail with return nil.
For enums:
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:
class BaseTool {
required init() { ... }
}
class SubTool: BaseTool {
required init() { ... }
}Setting Default Property Value with Closure
Use closures for complex defaults:
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]
}
}