Swift Programming – Properties

In this tutorial you’ll learn about properties in Swift. To follow along, it is recommended to have a Mac and the Xcode IDE installed on it. This tutorial makes use of the Xcode playground for compilation of the Swift codes. If you do not have a Mac, you may try using the open-source code editors which support different operating systems such as AtomSublimeText or VSCode.

Properties

Classes, Structures and Enumerations make use of properties to associate values. There are two types of properties, stored properties and computed properties. Stored properties are used to store values in constants or variables as part of an instance whilst computed properties are used to calculate values. You can use computed properties in classes, structures and enumerations whilst stored properties are allowed in classes and structures only.

Stored Properties

Let’s explore stored properties in an example.

struct Person {
    let name: String
    var age: Int
}

var person = Person(name: "Barry", age: 22)
print("\(person.name) is of age \(person.age)")
person.age = 23
print("\(person.name) is of age \(person.age)")

We defined a structure with the name Person and two stored properties name and age. Notice that the stored property name is a constant whilst age is a variable. Since we assigned a variable to the instance of Person, we can change the value of the variable stored property age. However, if instead of a variable we assigned a constant to the instance of Person, we cannot change the value of the variable stored property age. This is because structures are value types, assigning an instance of a structure to a constant, result in making all its stored properties constants as well. Note that for a class, if we assigned a constant to its instance, if its stored properties are variables, they can be changed.

Computed Properties

Let’s explore computed properties in an example.

struct SimpleMath {
    var numbers: [Int] = []
    var twoNumbers: (a: Int, b: Int) = (0, 0)
    
    // computed property with getter only
    var sum: Int {
        get {
            var output = 0
            
            for number in numbers {
                output += number
            }
            
            return output
        }
    }
    
    // computed property with getter/setter
    var min: Int {
        get {
            var output = numbers[numbers.count - 1]
            
            for number in numbers {
                if output > number {
                    output = number
                }
            }
            
            return output
        }
        
        set(newNumber) {
            numbers.append(newNumber)
        }
    }
    
    // computed property with getter/setter
    var max: Int {
        get {
            var output = numbers[numbers.count - 1]
            
            for number in numbers {
                if output < number {
                    output = number
                }
            }
            
            return output
        }
        
        // shorthand setter
        set {
            numbers.append(newValue)
        }
    }
    
    // computed property with shorthand getter
    var average: Double {
        get {
            Double(sum)/Double(numbers.count)
        }
    }
    
    // read-only computed property
    var multiplication: Int {
        return twoNumbers.a * twoNumbers.b
    }
}

let numbers = [2, 4, 6, 8, 10]
var simpleMath = SimpleMath(numbers: numbers)

print("Sum of \(numbers) is \(simpleMath.sum)")
print("Minimum number is \(simpleMath.min)")
print("Maximum number is \(simpleMath.max)")
print("Average is \(simpleMath.average)")

simpleMath.min = -2
simpleMath.max = 12

print("Sum of \(simpleMath.numbers) is \(simpleMath.sum)")
print("Minimum number is \(simpleMath.min)")
print("Maximum number is \(simpleMath.max)")
print("Average is \(simpleMath.average)")

let twoNumbers = (14, 25)
simpleMath.twoNumbers = twoNumbers

print("Multiplication of \(twoNumbers) is \(simpleMath.multiplication)")

Property Observers

You can observe and respond to properties using property observers willSet and didSet. You are allow to define either one or both of the property observers. The willSet property observer observes when a new value is about to be set whilst the didSet property observer observes when a new value has been set.

struct Grocery {
    var items: [String] = [] {
        willSet {
            print("\(newValue) will be added")
        }
        
        didSet {
            if oldValue != [] {
                print("\(oldValue) was previously added")
            }
        }
    }
}

var grocery = Grocery()
grocery.items = ["Fruits"]

print("numberList has \(grocery.items)")

var addedItems = grocery.items
addedItems.append("Vegetables")
addedItems.append("Yogurt")
grocery.items = addedItems

print("grocery has \(grocery.items)")

Reference

https://docs.swift.org/swift-book/LanguageGuide/Properties.html