Getters and Setters in Swift

Learn how to implement getters and setters for Swift properties, and learn about Swift 5.5 support for getters that can throw an error.

Getters and Setters in Swift

A getter in Swift allows access to a property, and a setter allows a property to be set. This post presents an overview of getters and setters, and examples of some Swift features related to getters and setters:

  1. Automatically Generated Getters and Setters
  2. get Getter
    a. get throws (new in Swift 5.5)
  3. set Setter
  4. willSet
  5. didSet
    a. ‘didSet’ cannot be provided together with a getter
    b. ‘willSet’ cannot be provided together with a getter
    c. ‘didSet’ cannot be provided together with a setter
    d. ‘willSet’ cannot be provided together with a setter

Automatically Generated Getters and Setters

When an instance property is defined in Swift using var, a getter and setter is automatically generated:

class Notes {
     var canSave = false
}

notes = Notes()
notes.canSave // Getter is available
notes.canSave = true // Setter is available

When an instance property is defined in Swift using let, only a getter is available:

class Store {
     let canOrder = false
}

store = Store()
store.canOrder // Getter is available

// This will not compile and cause the error:
// "Cannot assign to property 'canSave' 
//  is a 'let' constant"
store.canOrder = true

get Getter

One way to implement a variable property without an exposed setter is to indicate a variable as private(set):

class Store {
    private(set) var canOrder = false
}

// Create a store instance
store = Store()
store.canOrder // Getter is available

// This will not compile and cause the error:
// "Cannot assign to property: 'canOrder' 
//  setter is inaccessible"
store.canOrder = true

Another way to implement a variable property without an exposed setter is to use get. Often get is used to expose a getter to a private property:

class Store {
    private var _canOrder = false
    var canOrder: Bool {
        get { return _canOrder }
    }
}

// Create a store instance
store = Store()
store.canOrder // Getter is available

// This will not compile and cause the error:
// "Cannot assign to property: 'canOrder' 
//  is a get-only property"
store.canOrder = true

get throws (new in Swift 5.5)

Starting in Swift 5.5, throws is available for getters defined with get:

class Notes {
    func isDatabaseAvailable() throws -> Bool { 
        /* ... */ 
    }

    var canSave: Bool {
        get throws {
            return try isDatabaseAvailable()
        }
    }
}

notes = Notes()

do {
    if try notes.canSave {
        // Handle logic
    }
}
catch {
    // Handle error
}

set Setter

The set keyword can be used to implement an explicit setter in Swift. Often set is used to expose a setter for a private property and apply additional logic:

class Notes {
    func isDatabaseAvailable() -> Bool { 
        /* ... */ 
    }

    private var _canSave = false
    var canSave: Bool {
        get { return _canSave }
        set { 
            if isDatabaseAvailable() { 
                _canSave = newValue
            }
        }
    }
}

willSet

If explicit getters and setters using get and set are not defined, willSet can be used to take action before a new value is set for a property:

class Notes {
    func storePreviousSaveValue(_ canSave: Bool) {}
    var canSave = false {
        willSet {
            // Inside of willSet, the property 
            // canSave will be the old value,
            // before a new one is set
            storePreviousSaveValue(canSave)
        }
    }
}

// Creates an instance of notes with
// notes.canSave initialized to false
notes = Notes()

// willSet will be called while notes.canSave is
// false, so storePreviousSaveValue is called 
// with false, then notes.canSave is set to true
notes.canSave = true

didSet

If explicit getters and setters using get and set are not defined, didSet can be used to take action after a new value is set for a property:

class Notes {
    @IBOutlet var saveButton: UIButton?

    var canSave = false {
        didSet {
            // Inside of didSet, the property 
            // canSave will have the new value
            saveButton?.userInteractionEnabled = canSave
        }
    }
}

// Creates an instance of notes with
// notes.canSave initialized to false
notes = Notes()

// didSet will be called after notes.canSave is
// set to true, so saveButton?.userInteractionEnabled
// will be set to true
notes.canSave = true

'didSet' cannot be provided together with a getter

If only didSet and get are implemented, didSet will never be called because a get-only property cannot be set:

var canSave: Bool {
    // This causes the compiler error:
    // "‘didSet’ cannot be provided 
    //  together with a getter"
    get { /* ... */ }
    didSet { /* ... */ }
}

'willSet' cannot be provided together with a getter

If only willSet and get are implemented, willSet will never be called because a get-only property cannot be set:

var canSave: Bool {
    // This causes a compiler error:
    // "'willSet' cannot be provided 
    //  together with a getter"
    get { /* ... */ }
    willSet { /* ... */ }
}

'didSet' cannot be provided together with a setter

If only didSet and set are implemented, didSet should instead be implemented inside of the set setter:

var canSave: Bool {
    // This causes a compiler error:
    // "'didSet' cannot be provided 
    //  together with a setter"
    set { /* ... */ }
    didSet { /* ... */ }
}

// This is a better alternative:
var canSave: Bool {
    set { 
        canSave = newValue

        // Add code for didSet here,
        // after a new value is set
    }
}

'willSet' cannot be provided together with a setter

If only willSet and set are implemented, willSet should instead be implemented inside of the set setter:

var canSave: Bool {
    // This causes a compiler error:
    // "'willSet' cannot be provided 
    //  together with a setter"
    set { /* ... */ }
    willSet { /* ... */ }
}

// This is a better alternative:
var canSave: Bool {
    set { 
        // Add code for willSet here,
        // before a new value is set

        canSave = newValue
    }
}

Swift Getters and Setters

That’s it! By using get, set, willSet, and didSet you can implement getters and setters in Swift.