Structs, Classes & Memory
Two ways to model data
Swift gives you two main building blocks: struct and class. They look similar but behave very differently, and understanding that difference is one of the most important things in iOS development.
Value types (struct) vs reference types (class)
A struct is a value type: when you assign or pass it, you get a copy. A class is a reference type: assigning or passing it shares the same object — both names point to one thing in memory.
struct PointStruct { var x: Int }
class PointClass { var x = 0 }
var a = PointStruct(x: 1)
var b = a // b is a COPY
b.x = 99
print(a.x) // 1 (a is unchanged)
let c = PointClass()
let d = c // d points to the SAME object
d.x = 99
print(c.x) // 99 (both see the change!)
This single difference explains many iOS behaviours and bugs. Copies (structs) are predictable and safe; shared references (classes) are powerful but require care.
When to use which
- struct — for data: models, coordinates, settings. Apple recommends structs by default. SwiftUI is built almost entirely on them.
- class — when you need shared, mutable state, identity, or inheritance (e.g. a UIViewController, a ViewModel shared across screens).
Structs are great for models
struct User {
let id: Int
var name: String
var isPremium: Bool = false
}
var user = User(id: 1, name: "Anand")
var copy = user
copy.name = "Gaur" // doesn't affect 'user'
Classes and inheritance
class Animal {
var name: String
init(name: String) { self.name = name } // initializer
func sound() -> String { "..." }
}
class Dog: Animal {
override func sound() -> String { "Woof" }
}
Only classes support inheritance. Note the init initializer, which sets up the object’s properties.
Memory management: ARC
Swift automatically frees memory using Automatic Reference Counting (ARC). Every class instance has a count of how many things reference it; when the count hits zero, the object is freed. You don’t free memory manually — but you must avoid retain cycles, where two objects reference each other and neither can ever be freed.
// break a cycle with 'weak' (e.g. a child referring back to its parent)
class ViewModel {
weak var delegate: SomeDelegate? // weak doesn't keep the object alive
}
Structs don’t have this problem because they’re copied, not referenced — another reason to prefer them.
Common mistakes
- Expecting a struct to share changes like a class (it copies instead).
- Creating retain cycles with closures or delegates — use
weak self. - Reaching for a class when a simple struct would be safer.
Summary: Structs are copied value types (prefer them for data); classes are shared reference types with identity and inheritance. Swift frees memory automatically via ARC — just watch out for retain cycles and use weak to break them.