In Swift 5.8 a property is part of a class
or structure. On a Box class
, we might add a Width, Height. A property can be constant, but is often computed when accessed.
A property may be lazy, computed only on first access. With the property observers willSet
and didSet
we can run code as an object is modified.
This program declares a Square class
. On the class
, it has a "color" property of type String
. The init
method sets the color to a value provided.
var
because it is variable. A constant property uses let.class Square { var color: String init(color: String) { // Initialize the property. self.color = color } } // Create instance of class. var test = Square(color: "blue") // Print property value. print(test.color) // Reassign property and print it again. test.color = "red" print(test.color)blue red
This keyword indicates a property that is initialized as late as possible. So a lazy property is not initialized at the same time as the surrounding class
.
init
method like Color()
here—it cannot use just a value.Color()
is run earlier.class Color { var name: String init() { print("Color init called") self.name = "Blue" } } class Square { lazy var color: Color = Color() init() { print("Square init called") } } var test = Square() print("Before property use") // Use property. // ... It is initialized before first use. print(test.color.name) print(test.color.name) print("After property use")Square init called Before property use Color init called Blue Blue After property use
A computed property is not directly stored in memory. Instead it uses the "get" and "set" keywords to compute a result.
Init()
is run when the property is accessed. Here it returns the wingLength
times 2.newValue
"). This writes to the class
memory.NewValue
is a special name in a set computed property. It refers to the value the property is being set to.class Bird { var wingLength: Int var wingSpan: Int { get { // This computed property is based on wingLength. return wingLength * 2 } set { // Store the results of a computation. wingLength = newValue / 2 } } init() { self.wingLength = 0 } } var parrot = Bird() // We write and read the results of the computed properties. parrot.wingSpan = 2 print(parrot.wingSpan)2
Sometimes a property needs no "set" block. Instead it just returns a computed value each time it is used. A read-only property is ideal here.
class Car { var damageLevel: Int var isJunker: Bool { // This is a computed read-only property. return damageLevel >= 10 } init(damageLevel: Int) { self.damageLevel = damageLevel } } // This car has a high level of damage. let car1 = Car(damageLevel: 20) print(car1.isJunker) // This car has a low level of damage. let car2 = Car(damageLevel: 1) print(car2.isJunker)true false
These use the willSet
and didSet
keywords. They are special methods that are run before a property is set (willSet
) and after (didSet
).
WillSet
is triggered by an assignment to the property. It allows us to read the current value before it is changed.DidSet
lets us read both values—the previous one and the new one that was just set.OldValue
is a special name in the didSet
method. It is the previous value of the property before it was altered.class Volume { var level: Int = 0 { willSet { // Print current value. print("willSet") print(level) } didSet { // Print both oldValue and present value. print("didSet") print(oldValue) print(level) } } } // Use property on class. // ... Trigger willSet and didSet observers. var v = Volume() v.level = 4willSet 0 didSet 0 4
This is a special kind of property. With a subscript, we can access a value in a class
with arguments. The syntax is similar to an array access.
Properties control access to classes. They provide optimizations with the lazy keyword. In get and set we can compute dynamic properties.