0
0
iOS Swiftmobile~15 mins

Structs vs classes in iOS Swift - Trade-offs & Expert Analysis

Choose your learning style9 modes available
Overview - Structs vs classes
What is it?
Structs and classes are two ways to create custom data types in Swift. Both can hold values and functions, but they behave differently when copied or shared. Structs are value types, meaning each copy is independent, while classes are reference types, meaning copies share the same data. Understanding their differences helps you choose the right tool for your app's needs.
Why it matters
Choosing between structs and classes affects how your app manages data and memory. Without knowing the difference, you might accidentally change data in one place and see unexpected changes elsewhere. This can cause bugs that are hard to find. Using the right type keeps your app predictable, efficient, and easier to maintain.
Where it fits
Before learning this, you should understand basic Swift syntax and variables. After this, you can learn about protocols, inheritance, and memory management in Swift. This topic is a foundation for writing clean, safe, and efficient Swift code.
Mental Model
Core Idea
Structs copy their data when assigned or passed around, while classes share a single copy through references.
Think of it like...
Think of structs like photocopies of a document—each copy is separate and changes to one don’t affect the others. Classes are like shared Google Docs—everyone sees and edits the same document.
┌─────────────┐       copy       ┌─────────────┐
│   Struct A  │ ───────────────▶ │   Struct B  │
│ value: 10  │                 │ value: 10  │
└─────────────┘                 └─────────────┘

┌─────────────┐       ref        ┌─────────────┐
│   Class A   │ ───────────────▶ │   Class B   │
│ value: 10  │                 │ value: 10  │
└─────────────┘                 └─────────────┘

Changes in Struct B don’t affect A.
Changes in Class B affect A too.
Build-Up - 7 Steps
1
FoundationUnderstanding value types with structs
🤔
Concept: Structs are value types that copy their data when assigned or passed.
In Swift, a struct holds data and when you assign it to a new variable, Swift makes a full copy. For example: struct Point { var x: Int var y: Int } var p1 = Point(x: 1, y: 2) var p2 = p1 p2.x = 10 Here, changing p2.x does not change p1.x because p2 is a copy.
Result
p1.x remains 1, p2.x becomes 10, showing independent copies.
Understanding that structs copy data helps prevent unexpected changes when working with multiple variables.
2
FoundationUnderstanding reference types with classes
🤔
Concept: Classes are reference types that share the same instance when assigned or passed.
In Swift, a class holds data but when you assign it to a new variable, both variables point to the same instance. For example: class PointClass { var x: Int var y: Int init(x: Int, y: Int) { self.x = x self.y = y } } var c1 = PointClass(x: 1, y: 2) var c2 = c1 c2.x = 10 Here, changing c2.x also changes c1.x because c1 and c2 refer to the same object.
Result
Both c1.x and c2.x become 10, showing shared reference.
Knowing classes share references helps you manage shared data and avoid unintended side effects.
3
IntermediateMemory management differences explained
🤔Before reading on: do you think structs and classes use the same memory management? Commit to yes or no.
Concept: Structs are stored on the stack and copied, classes are stored on the heap and reference counted.
Structs are simple and stored on the stack, which is fast and temporary. Each copy is independent. Classes are stored on the heap, which allows shared access and uses reference counting to manage memory. When no references remain, the class instance is freed.
Result
Structs are faster for small data and safer from accidental sharing; classes allow shared mutable state but need careful memory management.
Understanding memory helps you write efficient code and avoid memory leaks or unexpected data sharing.
4
IntermediateMutability and how it differs
🤔Before reading on: do you think mutability works the same for structs and classes? Commit to yes or no.
Concept: Structs require explicit mutability to change properties; classes allow mutation through references.
Structs are immutable by default when assigned to constants (let). To change properties, you must mark methods or variables as 'mutating'. Classes allow changing properties anytime through references, even if assigned to constants, because the reference itself is constant, not the object.
Result
Structs enforce safer, controlled mutation; classes allow more flexible but riskier mutation.
Knowing mutability rules helps prevent bugs from unintended changes and improves code safety.
5
IntermediateInheritance and protocol conformance
🤔Before reading on: can structs inherit from other structs or classes? Commit to yes or no.
Concept: Classes support inheritance; structs do not but both can conform to protocols.
Classes can inherit properties and methods from other classes, enabling reuse and polymorphism. Structs cannot inherit but can adopt protocols to share behavior. This difference affects how you design your data models and code reuse.
Result
Classes enable flexible hierarchies; structs encourage composition over inheritance.
Understanding inheritance limits guides you to choose the right type for your app’s architecture.
6
AdvancedCopy-on-write optimization in structs
🤔Before reading on: do you think all struct copies always duplicate data immediately? Commit to yes or no.
Concept: Swift uses copy-on-write to delay copying struct data until it is modified.
For performance, Swift structs that hold large data (like arrays) don’t copy immediately. Instead, they share storage until one copy changes, then Swift makes a real copy. This optimization keeps structs efficient while preserving value semantics.
Result
Structs behave like independent copies but avoid unnecessary memory use until needed.
Knowing copy-on-write helps you trust structs for performance without losing safety.
7
ExpertUnexpected behavior with shared references in classes
🤔Before reading on: can two class variables unintentionally share state causing bugs? Commit to yes or no.
Concept: Classes can cause hidden bugs when multiple references modify shared data unexpectedly.
Because classes share references, changing data through one variable affects all others pointing to the same instance. This can cause bugs if you expect independent copies. Developers must carefully manage references or use copying methods to avoid surprises.
Result
Unintended shared state can cause hard-to-find bugs and unpredictable app behavior.
Understanding shared references is key to writing safe, bug-free class-based code.
Under the Hood
Structs are stored on the stack or inline in memory and copied entirely when assigned or passed. Classes are stored on the heap with a reference pointer. Swift uses Automatic Reference Counting (ARC) to track how many references point to a class instance and frees memory when count reaches zero. Structs use copy-on-write optimization to delay copying large data until mutation.
Why designed this way?
Swift designers chose structs as value types for safety and performance, encouraging immutable data and simpler reasoning. Classes provide flexibility with inheritance and shared mutable state, needed for complex object-oriented designs. This dual system balances safety and power, letting developers pick the best tool for their problem.
Stack (Structs):
┌─────────────┐
│  Point(x,y) │
│  x: 1      │
│  y: 2      │
└─────────────┘

Heap (Classes):
┌─────────────┐      ┌─────────────┐
│  c1 pointer │─────▶│ PointClass  │
│             │      │ x: 1       │
│             │      │ y: 2       │
└─────────────┘      └─────────────┘

ARC tracks pointers to heap objects.
Myth Busters - 4 Common Misconceptions
Quick: Does assigning a struct to a new variable create a shared reference? Commit yes or no.
Common Belief:Assigning a struct to a new variable creates a shared reference like a class.
Tap to reveal reality
Reality:Assigning a struct copies its data, creating an independent copy, not a shared reference.
Why it matters:Believing structs share references can lead to confusion about data changes and bugs when expecting independent copies.
Quick: Can structs inherit from other structs or classes? Commit yes or no.
Common Belief:Structs can inherit from other structs or classes just like classes do.
Tap to reveal reality
Reality:Structs cannot inherit from any type; only classes support inheritance in Swift.
Why it matters:Expecting inheritance in structs can cause design mistakes and misuse of protocols or composition.
Quick: Does mutating a property of a class instance require marking the method as mutating? Commit yes or no.
Common Belief:You must mark class methods as mutating to change properties, like with structs.
Tap to reveal reality
Reality:Classes do not require mutating keyword because their instances are reference types and can be changed freely.
Why it matters:Confusing mutability rules can cause unnecessary code complexity or misunderstanding of how data changes.
Quick: Do all struct copies immediately duplicate all data? Commit yes or no.
Common Belief:Every time you copy a struct, all its data is immediately duplicated in memory.
Tap to reveal reality
Reality:Swift uses copy-on-write optimization to delay copying large data until it is mutated.
Why it matters:Not knowing this can lead to incorrect assumptions about performance and memory use.
Expert Zone
1
Classes can implement custom copy methods to simulate value semantics, but this is manual and error-prone.
2
Structs with reference type properties can blur value semantics, requiring careful design to avoid unexpected sharing.
3
Using structs for large data types benefits from copy-on-write but can still cause performance issues if mutated frequently.
When NOT to use
Avoid classes when you want simple, safe, and predictable data copies; prefer structs. Avoid structs when you need inheritance, shared mutable state, or identity semantics. For shared state, consider using classes or specialized concurrency-safe types.
Production Patterns
Swift developers often use structs for models, data transfer objects, and immutable data. Classes are used for UI components, controllers, and shared resources. Copy-on-write structs like Array and String are standard library examples. Protocol-oriented design encourages structs with protocol conformance over class inheritance.
Connections
Functional Programming
Builds-on
Understanding structs as value types aligns with functional programming’s emphasis on immutable data and pure functions, improving code safety.
Memory Management
Builds-on
Knowing how ARC manages class instances helps prevent memory leaks and retain cycles in Swift apps.
Database Transactions
Analogy
Like structs copying data to avoid conflicts, database transactions isolate changes to prevent unintended side effects, showing a shared principle of safe data handling.
Common Pitfalls
#1Unexpected shared data changes when using classes.
Wrong approach:class User { var name: String init(name: String) { self.name = name } } var user1 = User(name: "Alice") var user2 = user1 user2.name = "Bob" print(user1.name) // Outputs "Bob" unexpectedly
Correct approach:class User { var name: String init(name: String) { self.name = name } func copy() -> User { return User(name: self.name) } } var user1 = User(name: "Alice") var user2 = user1.copy() user2.name = "Bob" print(user1.name) // Outputs "Alice" as expected
Root cause:Assuming class assignment creates independent copies instead of shared references.
#2Trying to inherit from a struct.
Wrong approach:struct Animal { var name: String } struct Dog: Animal { // Error: structs cannot inherit var breed: String }
Correct approach:protocol Animal { var name: String { get set } } struct Dog: Animal { var name: String var breed: String }
Root cause:Misunderstanding that structs do not support inheritance, requiring protocols for shared behavior.
#3Mutating struct properties without marking methods as mutating.
Wrong approach:struct Counter { var count = 0 func increment() { count += 1 // Error: cannot mutate in non-mutating method } }
Correct approach:struct Counter { var count = 0 mutating func increment() { count += 1 } }
Root cause:Not understanding that struct methods must be marked mutating to change properties.
Key Takeaways
Structs are value types that copy data, making them safe and predictable for independent data.
Classes are reference types that share data through pointers, enabling shared mutable state but requiring careful management.
Swift uses copy-on-write to optimize struct performance, delaying copies until mutation.
Mutability rules differ: structs require explicit mutating methods, classes allow mutation through references.
Choosing between structs and classes affects app safety, performance, and design; understanding their differences is essential for effective Swift development.