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 didSet once — a loop of 1,000 appends 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 / @State rely on to detect value-type changes.