{"id":2748,"date":"2026-02-05T12:13:44","date_gmt":"2026-02-05T12:13:44","guid":{"rendered":"https:\/\/demo.materiamedica.net\/demo6\/?p=2748"},"modified":"2026-02-05T12:13:44","modified_gmt":"2026-02-05T12:13:44","slug":"chapter-81-swift-class-vs-struct","status":"publish","type":"post","link":"https:\/\/demo.materiamedica.net\/demo6\/chapter-81-swift-class-vs-struct\/","title":{"rendered":"Chapter 81: Swift Class vs Struct"},"content":{"rendered":"<p dir=\"auto\"><strong>Class vs Struct in Swift<\/strong> \u2014 written exactly like a patient, experienced teacher sitting next to you with a playground open.<\/p>\n<p dir=\"auto\">We are going to go <strong>very slowly<\/strong>, with <strong>many small examples<\/strong>, real-life analogies, real-world decision patterns, common beginner mistakes, and the modern mental model that most good Swift developers use every day in 2025\u20132026.<\/p>\n<p dir=\"auto\">Let\u2019s start from the very beginning.<\/p>\n<h3 dir=\"auto\">1. The Core Difference \u2014 Value Type vs Reference Type<\/h3>\n<p dir=\"auto\">This is the <strong>single most important thing<\/strong> to understand. Everything else follows from this.<\/p>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"md\">Property<\/th>\n<th data-col-size=\"md\"><strong>Struct<\/strong> (Value Type)<\/th>\n<th data-col-size=\"lg\"><strong>Class<\/strong> (Reference Type)<\/th>\n<th data-col-size=\"lg\">Real-life analogy<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"md\">What is assigned \/ passed<\/td>\n<td data-col-size=\"md\">Full <strong>copy<\/strong> of all data<\/td>\n<td data-col-size=\"lg\"><strong>Reference<\/strong> (pointer) to the same object<\/td>\n<td data-col-size=\"lg\">Giving a photocopy vs giving the original photo<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Changing one variable affects others?<\/td>\n<td data-col-size=\"md\"><strong>No<\/strong> \u2014 each copy is independent<\/td>\n<td data-col-size=\"lg\"><strong>Yes<\/strong> \u2014 all variables point to the same object<\/td>\n<td data-col-size=\"lg\">Changing one photocopy doesn\u2019t change others<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Identity comparison (===)<\/td>\n<td data-col-size=\"md\"><strong>Not possible<\/strong> (value types don\u2019t have identity)<\/td>\n<td data-col-size=\"lg\"><strong>Possible<\/strong> \u2014 checks if same instance in memory<\/td>\n<td data-col-size=\"lg\">Asking \u201care these two the exact same photo print?\u201d<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Memory management<\/td>\n<td data-col-size=\"md\">Copied on write (Copy-on-Write for Array\/Dict\/String)<\/td>\n<td data-col-size=\"lg\">Reference counting (ARC)<\/td>\n<td data-col-size=\"lg\">Copies take more memory only when actually changed<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Thread safety (mutable shared state)<\/td>\n<td data-col-size=\"md\">Safer \u2014 copies are independent<\/td>\n<td data-col-size=\"lg\">Dangerous \u2014 needs careful synchronization<\/td>\n<td data-col-size=\"lg\">Copies are safe to modify from multiple threads<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Performance (small data)<\/td>\n<td data-col-size=\"md\">Usually faster (stack allocation possible)<\/td>\n<td data-col-size=\"lg\">Usually slower (heap + reference counting)<\/td>\n<td data-col-size=\"lg\">Small copies are cheap<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Can inherit<\/td>\n<td data-col-size=\"md\"><strong>No<\/strong><\/td>\n<td data-col-size=\"lg\"><strong>Yes<\/strong> (single inheritance)<\/td>\n<td data-col-size=\"lg\">Classes can have parents<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">Can be used as Dictionary key<\/td>\n<td data-col-size=\"md\"><strong>Yes<\/strong> (if Hashable)<\/td>\n<td data-col-size=\"lg\"><strong>Yes<\/strong> (but need careful Hashable)<\/td>\n<td data-col-size=\"lg\">Structs are easier for keys<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Golden rule used by almost every experienced Swift developer today<\/strong>:<\/p>\n<blockquote dir=\"auto\">\n<p dir=\"auto\"><strong>Default to struct for almost everything.<\/strong> <strong>Use class only when you really need one of these things:<\/strong><\/p>\n<ul dir=\"auto\">\n<li>reference semantics (shared mutable state)<\/li>\n<li>inheritance<\/li>\n<li>Objective-C interop \/ UIKit compatibility<\/li>\n<li>identity comparison (===)<\/li>\n<\/ul>\n<\/blockquote>\n<h3 dir=\"auto\">2. Side-by-side comparison with real examples<\/h3>\n<h4 dir=\"auto\">Example 1 \u2013 Mutability &amp; copying<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Swift<\/div>\n<div>\n<pre tabindex=\"0\"><code>\/\/ Struct \u2014 value type\r\nstruct Point {\r\n    var x: Int\r\n    var y: Int\r\n}\r\n\r\nvar p1 = Point(x: 10, y: 20)\r\nvar p2 = p1                \/\/ \u2190 full copy\r\n\r\np2.x = 100\r\n\r\nprint(p1.x)                \/\/ 10  \u2014 unchanged\r\nprint(p2.x)                \/\/ 100 \u2014 only p2 changed<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Swift<\/div>\n<div>\n<pre tabindex=\"0\"><code>\/\/ Class \u2014 reference type\r\nclass ReferencePoint {\r\n    var x: Int\r\n    var y: Int\r\n    \r\n    init(x: Int, y: Int) {\r\n        self.x = x\r\n        self.y = y\r\n    }\r\n}\r\n\r\nlet rp1 = ReferencePoint(x: 10, y: 20)\r\nlet rp2 = rp1              \/\/ \u2190 same object, just another reference\r\n\r\nrp2.x = 100\r\n\r\nprint(rp1.x)               \/\/ 100 \u2014 changed!\r\nprint(rp2.x)               \/\/ 100 \u2014 same object\r\nprint(rp1 === rp2)         \/\/ true \u2014 same instance<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Key takeaway<\/strong>:<\/p>\n<ul dir=\"auto\">\n<li><strong>Struct<\/strong> \u2192 changing one copy <strong>never<\/strong> affects others<\/li>\n<li><strong>Class<\/strong> \u2192 changing through any reference <strong>affects all references<\/strong><\/li>\n<\/ul>\n<h3 dir=\"auto\">3. Real-life examples \u2014 when developers choose struct vs class<\/h3>\n<h4 dir=\"auto\">Example 1 \u2013 Data model (almost always struct)<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Swift<\/div>\n<div>\n<pre tabindex=\"0\"><code>struct Product {\r\n    let id: String\r\n    let name: String\r\n    let price: Decimal\r\n    var quantity: Int = 1\r\n    \r\n    var subtotal: Decimal {\r\n        price * Decimal(quantity)\r\n    }\r\n    \r\n    mutating func increase(by step: Int = 1) {\r\n        quantity += step\r\n    }\r\n}\r\n\r\nvar cart: [Product] = []\r\ncart.append(Product(id: \"P001\", name: \"Earbuds\", price: 3499))\r\n\r\n\/\/ Copying is safe\r\nvar backupCart = cart\r\nbackupCart[0].increase(by: 2)\r\n\r\nprint(cart[0].quantity)      \/\/ still 1 \u2014 safe!\r\nprint(backupCart[0].quantity) \/\/ 3<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Why struct here?<\/strong><\/p>\n<ul dir=\"auto\">\n<li>No shared mutable state needed<\/li>\n<li>Copying is cheap (Copy-on-Write for Array)<\/li>\n<li>Value semantics \u2014 very predictable &amp; safe<\/li>\n<\/ul>\n<h4 dir=\"auto\">Example 2 \u2013 ViewController \/ view model (often class)<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Swift<\/div>\n<div>\n<pre tabindex=\"0\"><code>class CartViewModel: ObservableObject {\r\n    @Published var items: [CartItem] = []\r\n    @Published var total: Decimal = 0\r\n    \r\n    func addItem(_ item: CartItem) {\r\n        items.append(item)\r\n        updateTotal()\r\n    }\r\n    \r\n    private func updateTotal() {\r\n        total = items.reduce(0) { $0 + $1.subtotal }\r\n    }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Why class here?<\/strong><\/p>\n<ul dir=\"auto\">\n<li>Needs to be <strong>shared<\/strong> between views (@ObservedObject, @StateObject)<\/li>\n<li>Identity matters (same view model instance)<\/li>\n<li>Needs to <strong>notify observers<\/strong> when data changes (@Published)<\/li>\n<\/ul>\n<h3 dir=\"auto\">3. When to choose struct vs class \u2014 decision checklist<\/h3>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"xl\">Question \/ Need<\/th>\n<th data-col-size=\"md\">Choose Struct<\/th>\n<th data-col-size=\"md\">Choose Class<\/th>\n<th data-col-size=\"lg\">Typical real-world decision<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"xl\">Do you need <strong>identity<\/strong> (===)?<\/td>\n<td data-col-size=\"md\">No<\/td>\n<td data-col-size=\"md\">Yes<\/td>\n<td data-col-size=\"lg\">Shared state, view models<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xl\">Do you need <strong>inheritance<\/strong>?<\/td>\n<td data-col-size=\"md\">No<\/td>\n<td data-col-size=\"md\">Yes<\/td>\n<td data-col-size=\"lg\">UIKit\/AppKit view controllers<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xl\">Do you want <strong>value semantics<\/strong> (copy = independent)?<\/td>\n<td data-col-size=\"md\">Yes<\/td>\n<td data-col-size=\"md\">No<\/td>\n<td data-col-size=\"lg\">Data models, DTOs, value objects<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xl\">Is thread-safety important (mutable shared state)?<\/td>\n<td data-col-size=\"md\">Yes (safer)<\/td>\n<td data-col-size=\"md\">No (needs careful synchronization)<\/td>\n<td data-col-size=\"lg\">Modern apps prefer struct<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xl\">Is the data <strong>small<\/strong> &amp; <strong>frequently copied<\/strong>?<\/td>\n<td data-col-size=\"md\">Yes (Copy-on-Write efficient)<\/td>\n<td data-col-size=\"md\">No (reference counting overhead)<\/td>\n<td data-col-size=\"lg\">Almost always struct<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xl\">Do you need Objective-C interop?<\/td>\n<td data-col-size=\"md\">No<\/td>\n<td data-col-size=\"md\">Yes<\/td>\n<td data-col-size=\"lg\">UIKit, Core Data, etc.<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"xl\">Are you using SwiftUI \/ Combine heavily?<\/td>\n<td data-col-size=\"md\">Yes (structs + @State \/ @Binding)<\/td>\n<td data-col-size=\"md\">Sometimes (ObservableObject class)<\/td>\n<td data-col-size=\"lg\">Structs for most data<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Modern Swift recommendation (2025\u20132026)<\/strong>:<\/p>\n<blockquote dir=\"auto\">\n<p dir=\"auto\"><strong>Default to struct for almost everything<\/strong> Use <strong>class<\/strong> only when you <strong>really need<\/strong>:<\/p>\n<ul dir=\"auto\">\n<li>reference semantics (shared mutable state)<\/li>\n<li>inheritance<\/li>\n<li>Objective-C compatibility<\/li>\n<li>identity comparison (===)<\/li>\n<\/ul>\n<\/blockquote>\n<h3 dir=\"auto\">4. Very Common Beginner Mistakes &amp; Correct Habits<\/h3>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"lg\">Mistake<\/th>\n<th data-col-size=\"md\">Wrong \/ Risky code<\/th>\n<th data-col-size=\"lg\">Correct \/ Better habit<\/th>\n<th data-col-size=\"lg\">Why?<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"lg\">Using class by default \u201cjust in case\u201d<\/td>\n<td data-col-size=\"md\">class User { \u2026 } everywhere<\/td>\n<td data-col-size=\"lg\">Default to struct unless you need reference semantics<\/td>\n<td data-col-size=\"lg\">Value types are safer &amp; more predictable<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">Force-unwrapping in class\/struct<\/td>\n<td data-col-size=\"md\">self.user!.name<\/td>\n<td data-col-size=\"lg\">guard let user = user else { \u2026 }<\/td>\n<td data-col-size=\"lg\">Prevents crashes<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">Deep class inheritance<\/td>\n<td data-col-size=\"md\">5+ levels of class inheritance<\/td>\n<td data-col-size=\"lg\">Prefer composition or protocols<\/td>\n<td data-col-size=\"lg\">Deep hierarchies become hard to reason about<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">Forgetting mutating in struct methods<\/td>\n<td data-col-size=\"md\">func increaseAge() { age += 1 }<\/td>\n<td data-col-size=\"lg\">mutating func increaseAge() { age += 1 }<\/td>\n<td data-col-size=\"lg\">Compile error if missing<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">Sharing mutable class state without care<\/td>\n<td data-col-size=\"md\">static let shared = MyManager()<\/td>\n<td data-col-size=\"lg\">Prefer dependency injection over singletons<\/td>\n<td data-col-size=\"lg\">Singletons make testing &amp; reasoning hard<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">5. Small Practice \u2014 Try these<\/h3>\n<ol dir=\"auto\">\n<li>Create a Person<strong>struct<\/strong> with:\n<ul dir=\"auto\">\n<li>let name: String<\/li>\n<li>var age: Int<\/li>\n<li>mutating func haveBirthday()<\/li>\n<\/ul>\n<\/li>\n<li>Create a BankAccount<strong>struct<\/strong> like the example above\n<ul dir=\"auto\">\n<li>private var balance: Double<\/li>\n<li>init(initialDeposit:)<\/li>\n<li>mutating func deposit(amount:)<\/li>\n<li>mutating func withdraw(amount:) -&gt; Bool<\/li>\n<\/ul>\n<\/li>\n<li>Create a Location<strong>struct<\/strong>\n<ul dir=\"auto\">\n<li>let latitude: Double, longitude: Double<\/li>\n<li>var name: String?<\/li>\n<li>computed property coordinateString<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p dir=\"auto\">Paste your code here if you want feedback or want to see more polished versions!<\/p>\n<p dir=\"auto\">What would you like to explore next?<\/p>\n<ul dir=\"auto\">\n<li><strong>Struct vs Class<\/strong> \u2014 detailed comparison &amp; decision guide<\/li>\n<li><strong>Mutability<\/strong> inside structs (mutating methods)<\/li>\n<li><strong>Struct initializers<\/strong> (default, custom, memberwise)<\/li>\n<li><strong>Structs in SwiftUI<\/strong> (@State, value types, performance)<\/li>\n<li>Or move to another topic (optionals, arrays, closures, switch\u2026)<\/li>\n<\/ul>\n<p dir=\"auto\">Just tell me \u2014 we\u2019ll continue in the same clear, detailed, patient style \ud83d\ude0a<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Class vs Struct in Swift \u2014 written exactly like a patient, experienced teacher sitting next to you with a playground open. We are going to go very slowly, with many small examples, real-life analogies,&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[76],"tags":[],"class_list":["post-2748","post","type-post","status-publish","format-standard","hentry","category-swift"],"_links":{"self":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2748","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/comments?post=2748"}],"version-history":[{"count":1,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2748\/revisions"}],"predecessor-version":[{"id":2749,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2748\/revisions\/2749"}],"wp:attachment":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/media?parent=2748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/categories?post=2748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/tags?post=2748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}