{"id":"l-sw-2-1","courseId":"swift-essentials","lang":"en","kind":"lesson","summary":"Predict how structs and classes behave when you copy them, use mutating methods correctly, and break a closure retain cycle with weak self.","html":"<p>You open an expense, change its amount from 4.50 to 5.00 in an edit screen, then tap Cancel. Should the list still say 4.50? With a struct it does, automatically. With a class, the list already shows 5.00, because the edit screen and the list were looking at the same object. That one difference, <strong>value</strong> versus <strong>reference</strong> semantics, decides more about how an iOS app behaves than any other modelling choice.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Structs copy</h2>\n<p>Here is the expense type, now with <code dir=\"ltr\">var</code> properties so it can be edited:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Expense.swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Foundation</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">struct</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Expense</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> title: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount: Decimal</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> original </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Expense</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Coffee\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4.5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> draft </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> original</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">draft.amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 5</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(original.amount)   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 4.5</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(draft.amount)      </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 5</span></span></code></pre></div>\n<p><code dir=\"ltr\">var draft = original</code> makes a complete, independent copy. Editing the draft can’t affect the original, so the edit screen can work on a draft and the Cancel button costs nothing: you throw the draft away. Swift gives every struct a free <strong>memberwise initializer</strong>, which is why <code dir=\"ltr\">Expense(title:amount:)</code> works without you writing <code dir=\"ltr\">init</code>.</p>\n<p>Strings, arrays, dictionaries, <code dir=\"ltr\">Decimal</code> and <code dir=\"ltr\">Int</code> are all structs. That’s why <code dir=\"ltr\">var copy = amounts</code> in the collections lesson gave you an independent array. Swift makes those copies cheap by sharing storage until one side actually changes it.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">Classes share</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">final</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> class</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Account</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> balance: Decimal</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    init</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">balance</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">        self</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">.balance </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> balance</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> checking </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Account</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">balance</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">500</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sameAccount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> checking</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">sameAccount.balance </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 50</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(checking.balance)          </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 450</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(checking </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">===</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sameAccount)  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// true: same instance</span></span></code></pre></div>\n<p>A class instance lives in one place; variables hold references to it. <code dir=\"ltr\">let sameAccount = checking</code> copies the reference, so both names point at the same account. <code dir=\"ltr\">===</code> asks “is this the very same instance?”, a question that makes no sense for structs. Classes need an explicit <code dir=\"ltr\">init</code> for stored properties without defaults. Mark them <code dir=\"ltr\">final</code> unless you plan to subclass, which is rare in modern Swift.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 700 250\" role=\"img\" aria-labelledby=\"l-sw-2-1-t1\"><defs><marker id=\"arrow-l-sw-2-1-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-sw-2-1-t1\">On the left, original and draft are two separate Expense boxes with amounts 4.5 and 5. On the right, checking and sameAccount are two names whose arrows point to one shared Account box with balance 450.</title>\n  <text class=\"d-label-strong\" x=\"170\" y=\"28\" text-anchor=\"middle\">struct: two values</text>\n  <rect class=\"d-box-success\" x=\"30\" y=\"60\" width=\"130\" height=\"80\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"95\" y=\"90\" text-anchor=\"middle\">original</text>\n  <text class=\"d-label\" x=\"95\" y=\"118\" text-anchor=\"middle\">amount 4.5</text>\n  <rect class=\"d-box-success\" x=\"190\" y=\"60\" width=\"130\" height=\"80\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"255\" y=\"90\" text-anchor=\"middle\">draft</text>\n  <text class=\"d-label\" x=\"255\" y=\"118\" text-anchor=\"middle\">amount 5</text>\n  <text class=\"d-label-muted\" x=\"175\" y=\"175\" text-anchor=\"middle\">independent copies</text>\n  <path class=\"d-line d-dashed\" d=\"M350 20 L350 230\"/>\n  <text class=\"d-label-strong\" x=\"530\" y=\"28\" text-anchor=\"middle\">class: one object</text>\n  <rect class=\"d-box\" x=\"390\" y=\"60\" width=\"120\" height=\"40\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"450\" y=\"85\" text-anchor=\"middle\">checking</text>\n  <rect class=\"d-box\" x=\"560\" y=\"60\" width=\"130\" height=\"40\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"625\" y=\"85\" text-anchor=\"middle\">sameAccount</text>\n  <path class=\"d-arrow\" d=\"M450 100 L515 160\" marker-end=\"url(#arrow-l-sw-2-1-1)\"/>\n  <path class=\"d-arrow\" d=\"M625 100 L560 160\" marker-end=\"url(#arrow-l-sw-2-1-1)\"/>\n  <rect class=\"d-box-primary\" x=\"460\" y=\"165\" width=\"160\" height=\"60\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"540\" y=\"190\" text-anchor=\"middle\">Account</text>\n  <text class=\"d-label\" x=\"540\" y=\"212\" text-anchor=\"middle\">balance 450</text>\n</svg><figcaption>Copying a struct versus copying a class reference</figcaption></figure>\n<h2 id=\"sec-3\" tabindex=\"-1\">let means different things</h2>\n<p><code dir=\"ltr\">let</code> freezes whatever the name holds. For a struct, the name holds the whole value, so nothing inside can change. For a class, the name holds a reference, so the reference is fixed but the object’s <code dir=\"ltr\">var</code> properties are still changeable, which is exactly why <code dir=\"ltr\">sameAccount.balance -= 50</code> compiled even though <code dir=\"ltr\">sameAccount</code> is a <code dir=\"ltr\">let</code>.</p>\n<p>Struct methods that change properties must say so with <code dir=\"ltr\">mutating</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">struct</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Budget</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit: Decimal</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent: Decimal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> remaining: Decimal { limit </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent }   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// computed property</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    mutating</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> func</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> record</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">_</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount: Decimal) {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        spent </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> food </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Budget</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">limit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">300</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">food.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">record</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(food.remaining)   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 258</span></span></code></pre></div>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Calling a mutating method on a let</span></p>\n<p><code dir=\"ltr\">let food = Budget(limit: 300)</code> followed by <code dir=\"ltr\">food.record(42)</code> fails with “cannot use mutating member on immutable value: ‘food’ is a ‘let’ constant”. The compiler is right: you said this budget never changes. Make it <code dir=\"ltr\">var</code>, or rethink whether it should change.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">Which one to choose</h2>\n<p>Apple’s guidance, and mine, is to <strong>start with a struct</strong>. Values are easier to reason about because nothing can change them behind your back, and they’re safe to pass between threads, which matters a great deal in Swift 6. Use a class when you need <strong>identity</strong>: one shared thing that several parts of the app see and update. In Pocket Budget, each <code dir=\"ltr\">Expense</code> is a struct, and the store that owns the list and that several screens observe will be a class. The Observation framework’s <code dir=\"ltr\">@Observable</code> and SwiftData’s <code dir=\"ltr\">@Model</code>, which you’ll use later, both require classes for exactly this reason.</p>\n<p>A quick test when you’re unsure: imagine handing a copy to another screen. If that screen should get its own version to edit freely, you want a struct. If it should see every change the rest of the app makes, and changes it makes should show up everywhere, you want a class. Most data in most apps passes the first test.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">ARC and retain cycles</h2>\n<p>Classes are freed by <strong>automatic reference counting</strong> (ARC): each strong reference adds one to a count, and when the count reaches zero the object is freed and its <code dir=\"ltr\">deinit</code> runs. Trouble starts when an object stores a closure that captures the object itself:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">BudgetAlert.swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">final</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> class</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> BudgetAlert</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> threshold: Decimal</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> onTrigger: (() </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Void</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    init</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">threshold</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">        self</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">.threshold </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> threshold</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    func</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> arm</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        onTrigger </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { [</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">weak</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> self</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">            guard</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> let</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> self</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> else</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">            print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Spent more than </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">self</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">.</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">threshold</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    deinit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"BudgetAlert freed\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Without <code dir=\"ltr\">[weak self]</code>, the alert owns the closure and the closure owns the alert. Neither count ever reaches zero, <code dir=\"ltr\">deinit</code> never runs, and you’ve leaked memory. The capture list <code dir=\"ltr\">[weak self]</code> makes the closure’s reference weak and optional, so <code dir=\"ltr\">guard let self</code> unwraps it while it’s still alive. A struct on its own can’t form these cycles, which is one more reason structs are the default.</p>\n<p>Value or reference is half of modelling. The other half is describing data that comes in different shapes, like an expense paid by card versus cash. That’s what enums with associated values are for, and they’re next.</p>\n","toc":[{"id":"sec-1","text":"Structs copy","level":2},{"id":"sec-2","text":"Classes share","level":2},{"id":"sec-3","text":"let means different things","level":2},{"id":"sec-4","text":"Which one to choose","level":2},{"id":"sec-5","text":"ARC and retain cycles","level":2}],"takeaways":["Assigning a struct makes an independent copy; assigning a class instance makes a second reference to the same object.","A <code dir=\"ltr\">let</code> struct is frozen all the way down, while a <code dir=\"ltr\">let</code> class reference can still have its <code dir=\"ltr\">var</code> properties changed.","Struct methods that change properties must be marked <code dir=\"ltr\">mutating</code>, and they can only be called on a <code dir=\"ltr\">var</code>.","Default to structs for your data; reach for a class when you need shared identity, such as one object many screens observe.","A class that stores a closure which captures <code dir=\"ltr\">self</code> strongly creates a retain cycle; capture <code dir=\"ltr\">[weak self]</code> to break it."],"further":[{"title":"Choosing Between Structures and Classes","url":"https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes"},{"title":"Structures and Classes","url":"https://docs.swift.org/swift-book/documentation/the-swift-programming-language/classesandstructures/"},{"title":"Automatic Reference Counting","url":"https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/"}],"quiz":[{"q":"<p><code dir=\"ltr\">Budget</code> is a struct with a <code dir=\"ltr\">mutating func record(_:)</code>. Why does <code dir=\"ltr\">let food = Budget(limit: 300); food.record(42)</code> fail to compile?</p>","options":[{"text":"Structs can’t have methods that change properties.","why":"They can, as long as the method is marked <code dir=\"ltr\">mutating</code> and called on a <code dir=\"ltr\">var</code>."},{"text":"<code dir=\"ltr\">food</code> is a <code dir=\"ltr\">let</code>, so the whole value is immutable and mutating methods are off-limits.","why":"Correct. Change it to <code dir=\"ltr\">var food</code> and the call compiles."},{"text":"The method needs to be marked <code dir=\"ltr\">static</code>.","why":"<code dir=\"ltr\">static</code> methods belong to the type, not to one budget. That would change the design, not fix the error."}],"answer":1},{"q":"<p><code dir=\"ltr\">Account</code> is a class. <code dir=\"ltr\">let a = Account(balance: 500); let b = a; b.balance -= 50</code>. What is <code dir=\"ltr\">a.balance</code>?</p>","options":[{"text":"450","why":"Correct. <code dir=\"ltr\">a</code> and <code dir=\"ltr\">b</code> refer to the same object, so a change through one is visible through the other."},{"text":"500","why":"That’s struct behaviour. Class assignment copies the reference, not the object."},{"text":"It doesn’t compile because <code dir=\"ltr\">b</code> is a <code dir=\"ltr\">let</code>.","why":"<code dir=\"ltr\">let</code> freezes the reference <code dir=\"ltr\">b</code>, not the object’s <code dir=\"ltr\">var</code> properties."}],"answer":0},{"q":"<p>Which data in Pocket Budget is the best fit for a class rather than a struct?</p>","options":[{"text":"A single expense with a title, amount and date.","why":"An expense is plain data with no identity beyond its values; a struct keeps copies independent and safe."},{"text":"A pair of start and end dates for a report.","why":"Small immutable data is the textbook struct."},{"text":"The one shared store that several screens read and update.","why":"Correct. Several screens need to see the same instance, which is exactly what reference semantics gives you."},{"text":"A currency code such as “EUR”.","why":"A code is a value; a struct or even a plain <code dir=\"ltr\">String</code> fits better."}],"answer":2},{"q":"<p>A class stores <code dir=\"ltr\">onTrigger = { print(self.threshold) }</code> in its own property. What’s the consequence?</p>","options":[{"text":"The closure gets a copy of <code dir=\"ltr\">self</code>, so changes to the object are invisible.","why":"Classes are never copied by capture. The closure holds a strong reference to the same object."},{"text":"Swift refuses to compile any closure that mentions <code dir=\"ltr\">self</code>.","why":"Swift only makes you write <code dir=\"ltr\">self.</code> explicitly in escaping closures; it doesn’t forbid capturing it."},{"text":"Nothing special; ARC frees both when the screen closes.","why":"ARC can’t free objects that keep each other alive. That’s the whole problem."},{"text":"Object and closure keep each other alive, so the object is never freed.","why":"Correct. Capture <code dir=\"ltr\">[weak self]</code> so the closure doesn’t own the object."}],"answer":3}],"exercise":{"kind":"choice","options":["a","b","c","d"],"correct":["b"],"title":"Struct or class: predict the output","prompt":"<p><code dir=\"ltr\">Limit</code> is a struct and <code dir=\"ltr\">Wallet</code> is a class. Read the snippet and predict the single line it prints.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Foundation</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">struct</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Limit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount: Decimal</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">final</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> class</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Wallet</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> balance: Decimal</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    init</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">balance</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal) { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">self</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">.balance </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> balance }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> food </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Limit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">300</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> fun </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> food</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">fun.amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 100</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> mine </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Wallet</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">balance</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">500</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> shared </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> mine</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">shared.balance </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 50</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(food.amount, fun.amount, mine.balance)</span></span></code></pre></div>\n","hints":["Treat the two halves separately: first the struct, then the class.","After <code dir=\"ltr\">var fun = food</code>, how many <code dir=\"ltr\">Limit</code> values exist?","After <code dir=\"ltr\">let shared = mine</code>, how many <code dir=\"ltr\">Wallet</code> objects exist?"],"explanation":"<p><code dir=\"ltr\">var fun = food</code> copies the struct, so changing <code dir=\"ltr\">fun.amount</code> to 100 leaves <code dir=\"ltr\">food.amount</code> at 300. <code dir=\"ltr\">let shared = mine</code> copies only the reference: there is still one <code dir=\"ltr\">Wallet</code>, and subtracting 50 through <code dir=\"ltr\">shared</code> is visible through <code dir=\"ltr\">mine</code>. The output is <code dir=\"ltr\">300 100 450</code>.</p>\n<p>Notice that <code dir=\"ltr\">shared</code> is a <code dir=\"ltr\">let</code> and the subtraction still compiled. <code dir=\"ltr\">let</code> fixes which object <code dir=\"ltr\">shared</code> points to, not the object’s <code dir=\"ltr\">var</code> properties.</p>\n","checkLabels":{},"optionText":{"a":{"text":"<code dir=\"ltr\">100 100 450</code>","why":"This treats the struct like a class. <code dir=\"ltr\">var fun = food</code> made a separate copy, so <code dir=\"ltr\">food</code> keeps 300."},"b":{"text":"<code dir=\"ltr\">300 100 450</code>","why":"Correct. The struct copy is independent, and the two class references share one wallet."},"c":{"text":"<code dir=\"ltr\">300 100 500</code>","why":"This treats the class like a struct. <code dir=\"ltr\">shared</code> and <code dir=\"ltr\">mine</code> are the same object, so the 50 is gone from both."},"d":{"text":"It doesn’t compile: <code dir=\"ltr\">shared</code> is a <code dir=\"ltr\">let</code>.","why":"<code dir=\"ltr\">let</code> freezes the reference, not the object’s <code dir=\"ltr\">var</code> properties, so <code dir=\"ltr\">shared.balance -= 50</code> is legal."}}},"words":691,"readMinutes":3}