Skip to main content

Swift Class Properties

Properties are essential components of classes in Swift that allow you to store and compute values. Unlike simple variables, properties come with additional capabilities that make Swift's object-oriented programming powerful and flexible.

Introduction to Class Properties

Properties in Swift classes represent the attributes or characteristics of the objects created from those classes. They provide a way to access and modify the data associated with a class instance.

Swift offers several types of properties:

  • Stored properties
  • Computed properties
  • Property observers
  • Type properties

Let's explore each type with examples and practical applications.

Stored Properties

Stored properties are the most basic form of properties that simply store a value as part of an instance of a class.

Basic Syntax

swift
class Person {
var name: String
var age: Int

init(name: String, age: Int) {
self.name = name
self.age = age
}
}

// Creating an instance
let person = Person(name: "Alice", age: 28)
print(person.name) // Output: Alice
print(person.age) // Output: 28

Constant and Variable Stored Properties

Swift allows you to declare stored properties as either constants (let) or variables (var):

swift
class Car {
let manufacturer: String // Constant property - cannot be changed after initialization
var currentSpeed: Double // Variable property - can be modified

init(manufacturer: String) {
self.manufacturer = manufacturer
self.currentSpeed = 0.0
}
}

let myCar = Car(manufacturer: "Toyota")
// myCar.manufacturer = "Honda" // This would cause an error
myCar.currentSpeed = 60.5 // This is allowed

Default Values

You can provide default values for stored properties:

swift
class Counter {
var count: Int = 0 // Default value
var maxValue = 100 // Type inference with default value

func increment() {
if count < maxValue {
count += 1
}
}
}

let myCounter = Counter()
print(myCounter.count) // Output: 0
myCounter.increment()
print(myCounter.count) // Output: 1

Computed Properties

Computed properties don't actually store a value; instead, they provide a getter and an optional setter to retrieve and set other properties indirectly.

Basic Syntax

swift
class Rectangle {
var width: Double
var height: Double

// Computed property
var area: Double {
return width * height
}

init(width: Double, height: Double) {
self.width = width
self.height = height
}
}

let rectangle = Rectangle(width: 5.0, height: 3.0)
print(rectangle.area) // Output: 15.0

Getters and Setters

Computed properties can have both getters and setters:

swift
class Temperature {
var celsius: Double

// Computed property with getter and setter
var fahrenheit: Double {
get {
return (celsius * 9/5) + 32
}
set {
celsius = (newValue - 32) * 5/9
}
}

init(celsius: Double) {
self.celsius = celsius
}
}

let temp = Temperature(celsius: 25.0)
print(temp.fahrenheit) // Output: 77.0

temp.fahrenheit = 86.0
print(temp.celsius) // Output: 30.0

Read-Only Computed Properties

If you only provide a getter but no setter, you have a read-only computed property:

swift
class Circle {
var radius: Double

// Read-only computed property
var area: Double {
return Double.pi * radius * radius
}

init(radius: Double) {
self.radius = radius
}
}

let circle = Circle(radius: 2.0)
print(circle.area) // Output: 12.566370614359172
// circle.area = 20 // Error: Cannot assign to property: 'area' is a get-only property

Property Observers

Property observers let you observe and respond to changes in a property's value. You can add observers to any stored property, and they're called every time a property's value is set.

willSet and didSet

swift
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}

let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// Output:
// About to set totalSteps to 200
// Added 200 steps

stepCounter.totalSteps = 360
// Output:
// About to set totalSteps to 360
// Added 160 steps

Practical Example with Property Observers

swift
class BankAccount {
var accountName: String
var balance: Double {
didSet {
if balance < 0 {
print("WARNING: Negative balance detected!")
}

if balance != oldValue {
let change = balance - oldValue
let action = change > 0 ? "deposit" : "withdrawal"
let amount = abs(change)

transactionHistory.append("\(Date()): \(action) of $\(amount)")
}
}
}
var transactionHistory: [String] = []

init(accountName: String, initialBalance: Double) {
self.accountName = accountName
self.balance = initialBalance
}

func printTransactions() {
for transaction in transactionHistory {
print(transaction)
}
}
}

let account = BankAccount(accountName: "John's Savings", initialBalance: 100.0)
account.balance += 50.0
account.balance -= 75.0
account.printTransactions()
// Output will include two transaction records

Lazy Properties

Lazy stored properties are properties whose initial value isn't calculated until the first time it's used. This is useful when the initial value for a property is dependent on outside factors, or when it's computationally expensive to set up.

swift
class DataManager {
lazy var data: [String] = {
// This could be an expensive operation like loading a file
print("Initializing data array...")
return ["One", "Two", "Three"]
}()
}

let manager = DataManager()
print("DataManager initialized")
// At this point, the data property hasn't been initialized yet

print(manager.data) // Now the data property gets initialized
// Output:
// DataManager initialized
// Initializing data array...
// ["One", "Two", "Three"]

Type Properties

Type properties belong to the type itself, not to instances of that type. They're useful for defining properties that are common to all instances of a particular type.

Static Properties

swift
class SomeClass {
static var storedTypeProperty = "Some value"
static let constantTypeProperty = "Another value"

static var computedTypeProperty: Int {
return 42
}
}

print(SomeClass.storedTypeProperty) // Output: Some value
print(SomeClass.computedTypeProperty) // Output: 42

Practical Example of Type Properties

swift
class TemperatureConverter {
static let celsiusZeroInFahrenheit = 32.0
static let celsiusBoilingInFahrenheit = 212.0

// Type method to determine if water would freeze at a given temperature
static func willWaterFreeze(atFahrenheit fahrenheit: Double) -> Bool {
return fahrenheit <= celsiusZeroInFahrenheit
}
}

print("Water freezing point: \(TemperatureConverter.celsiusZeroInFahrenheit)°F")
print("Will water freeze at 30°F? \(TemperatureConverter.willWaterFreeze(atFahrenheit: 30))")
// Output:
// Water freezing point: 32.0°F
// Will water freeze at 30°F? true

Real-World Application Example

Let's build a more complex example that combines different types of properties to model a real-world system:

swift
class Student {
let id: String
var name: String
private var _grades: [Double] = []

// Computed property for read-only access to grades
var grades: [Double] {
return _grades
}

// Computed property for GPA
var gpa: Double {
if _grades.isEmpty {
return 0.0
}
let sum = _grades.reduce(0, +)
return sum / Double(_grades.count)
}

// Property with observers
var isHonorRoll: Bool = false {
didSet {
if isHonorRoll && !oldValue {
print("\(name) has made the honor roll!")
}
}
}

// Type property for requirements
static let honorRollThreshold = 3.5

init(id: String, name: String) {
self.id = id
self.name = name
}

func addGrade(_ grade: Double) {
_grades.append(grade)
// Check honor roll status
isHonorRoll = gpa >= Student.honorRollThreshold
}
}

// Using the Student class
let alice = Student(id: "A12345", name: "Alice Johnson")
alice.addGrade(3.7)
alice.addGrade(3.9)
alice.addGrade(3.8)

print("\(alice.name)'s GPA: \(alice.gpa)")
print("Grades: \(alice.grades)")

// Output:
// Alice Johnson has made the honor roll!
// Alice Johnson's GPA: 3.8
// Grades: [3.7, 3.9, 3.8]

Summary

Swift class properties are powerful tools that allow you to define the characteristics and behaviors of your classes:

  • Stored properties hold values that are part of the instance
  • Computed properties calculate values on-the-fly based on other properties
  • Property observers respond to changes in property values
  • Lazy properties defer initialization until first access
  • Type properties belong to the class itself rather than instances

Understanding these different types of properties enables you to write more expressive, flexible, and powerful Swift code.

Exercises

  1. Create a BankAccount class with a balance property that doesn't allow negative values.
  2. Design a Circle class with a radius property and computed properties for area, diameter, and circumference.
  3. Build a Team class with a property observer that tracks changes in the team roster.
  4. Implement a Calculator class with type properties for mathematical constants.
  5. Create a Book class with lazy properties for content that is only loaded when needed.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)