Browse Questions
Answer: Arrays and structs are value types, so changing anything inside them — appending, editing an element, or changing a nested field — counts as setting the whole property to a new value.
Code Example:
struct User {
var name: String
}
class ViewModel {
var users: [User] = [] {
didSet { print("users changed: \(users.count)") }
}
}
let vm = ViewModel()
vm.users.append(User(name: "Mia")) // ✅ didSet
vm.users[0].name = "Lina" // ✅ didSet — nested mutation
vm.users.sort { $0.name < $1.name } // ✅ didSet
If User were a class:
final class User { var name: String; init(name: String) { self.name = name } }
vm.users[0].name = "Lina" // ❌ NO didSet — the array still holds the same reference
Key Points:
- Each mutation fires
didSetonce — a loop of 1,000appends fires it 1,000 times. Batch changes into a local copy and assign once if the observer is expensive (e.g. reloads a table view). - This is the same mechanism SwiftUI's
@Published/@Staterely on to detect value-type changes.