<?xml version="1.0" encoding="UTF-8" standalone="no"?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0"><channel><title>FlutDev</title><description>Flutter transforms the entire app development process. Build, test, and deploy beautiful mobile, web, desktop, and embedded apps from a single codebase.</description><managingEditor>noreply@blogger.com (Lokesh Jangid)</managingEditor><pubDate>Mon, 23 Feb 2026 22:16:45 -0800</pubDate><generator>Blogger http://www.blogger.com</generator><openSearch:totalResults xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">173</openSearch:totalResults><openSearch:startIndex xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">1</openSearch:startIndex><openSearch:itemsPerPage xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">5</openSearch:itemsPerPage><link>https://flutdev.blogspot.com/</link><language>en-us</language><itunes:explicit>no</itunes:explicit><itunes:image href="https://blogger.googleusercontent.com/img/a/AVvXsEjHfvut4TbvXsPmGm2RogFjjENDjMpQ3ci_vDH-2tWTDIew_Uvnf_H47Kh4ehMbObtINna-WtEC--0hOZMcja4dNteOgFa8p8M3H_nDxtCw5VKdDk-q9AijbkcvWYOgdQn2A69Q7XBxAXIy4XmQ-y-2khcmzVterWRTyYeIeqKbdnzmLyouEKlpxNWrqQ=s200"/><itunes:subtitle>Flutter transforms the entire app development process. Build, test, and deploy beautiful mobile, web, desktop, and embedded apps from a single codebase.</itunes:subtitle><itunes:category text="Education"><itunes:category text="Educational Technology"/></itunes:category><itunes:owner><itunes:email>noreply@blogger.com</itunes:email></itunes:owner><item><title>&#127822; SwiftUI Interview Questions &amp;amp; Answers</title><link>https://flutdev.blogspot.com/2026/02/swiftui-interview-questions-answers.html</link><category>IOS</category><category>Swift</category><category>SwiftUI</category><author>noreply@blogger.com (Lokesh Jangid)</author><pubDate>Mon, 23 Feb 2026 22:16:00 -0800</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7439341812408440578.post-825798000819926935</guid><description>&lt;blockquote&gt;&lt;p&gt;A comprehensive guide covering everything from fundamentals to advanced SwiftUI concepts — structured point by point with visual diagrams.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id="1-what-is-swiftui-"&gt;1. What is SwiftUI?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is SwiftUI and when was it introduced?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SwiftUI is Apple's &lt;strong&gt;modern declarative UI framework&lt;/strong&gt; introduced at WWDC 2019 (iOS 13+). It allows developers to build user interfaces for &lt;strong&gt;all Apple platforms&lt;/strong&gt; — iOS, macOS, watchOS, and tvOS — using a &lt;strong&gt;single, unified Swift codebase&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="-key-advantages"&gt;✅ Key Advantages&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                    SwiftUI Advantages                        │
├─────────────────────┬───────────────────────────────────────┤
│ Declarative Syntax  │ &lt;span class="hljs-keyword"&gt;Describe&lt;/span&gt; WHAT the UI looks &lt;span class="hljs-keyword"&gt;like&lt;/span&gt;,      │
│                     │ &lt;span class="hljs-keyword"&gt;not&lt;/span&gt; HOW &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; &lt;span class="hljs-keyword"&gt;build&lt;/span&gt; it step &lt;span class="hljs-keyword"&gt;by&lt;/span&gt; step       │
├─────────────────────┼───────────────────────────────────────┤
│ Live Preview        │ See &lt;span class="hljs-built_in"&gt;real&lt;/span&gt;-&lt;span class="hljs-keyword"&gt;time&lt;/span&gt; UI changes &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; Xcode     │
│                     │ &lt;span class="hljs-keyword"&gt;without&lt;/span&gt; recompiling the entire app     │
├─────────────────────┼───────────────────────────────────────┤
│ &lt;span class="hljs-keyword"&gt;Less&lt;/span&gt; Code           │ Achieve complex layouts &lt;span class="hljs-keyword"&gt;with&lt;/span&gt; &lt;span class="hljs-keyword"&gt;far&lt;/span&gt;       │
│                     │ fewer &lt;span class="hljs-keyword"&gt;lines&lt;/span&gt; &lt;span class="hljs-keyword"&gt;than&lt;/span&gt; UIKit                 │
├─────────────────────┼───────────────────────────────────────┤
│ Multi-Platform      │ One codebase targets iOS, macOS,       │
│                     │ watchOS, &lt;span class="hljs-keyword"&gt;and&lt;/span&gt; tvOS                      │
├─────────────────────┼───────────────────────────────────────┤
│ Built-&lt;span class="hljs-keyword"&gt;in&lt;/span&gt; Animation  │ &lt;span class="hljs-keyword"&gt;Add&lt;/span&gt; smooth animations &lt;span class="hljs-keyword"&gt;with&lt;/span&gt; simple      │
│                     │ modifiers &lt;span class="hljs-keyword"&gt;and&lt;/span&gt; state changes            │
├─────────────────────┼───────────────────────────────────────┤
│ &lt;span class="hljs-keyword"&gt;Auto&lt;/span&gt; Accessibility  │ &lt;span class="hljs-keyword"&gt;Default&lt;/span&gt; accessibility support baked    │
│                     │ &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; &lt;span class="hljs-keyword"&gt;without&lt;/span&gt; extra configuration         │
└─────────────────────┴───────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-basic-swiftui-example"&gt;&#128187; Basic SwiftUI Example&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;import&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt;

&lt;span class="hljs-selector-tag"&gt;struct&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;ContentView&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;View&lt;/span&gt; {
    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;some&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;View&lt;/span&gt; {
        &lt;span class="hljs-selector-tag"&gt;VStack&lt;/span&gt; {
            &lt;span class="hljs-selector-tag"&gt;Image&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;systemName&lt;/span&gt;: &lt;span class="hljs-string"&gt;"globe"&lt;/span&gt;)
                &lt;span class="hljs-selector-class"&gt;.imageScale&lt;/span&gt;(.large)
                &lt;span class="hljs-selector-class"&gt;.foregroundColor&lt;/span&gt;(.accentColor)
            &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Hello, SwiftUI!"&lt;/span&gt;)
                &lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(.title)
                &lt;span class="hljs-selector-class"&gt;.bold&lt;/span&gt;()
        }
        &lt;span class="hljs-selector-class"&gt;.padding&lt;/span&gt;()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="2-swiftui-vs-uikit"&gt;2. SwiftUI vs UIKit&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What are the key differences between SwiftUI and UIKit?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                   &lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt;  &lt;span class="hljs-selector-tag"&gt;vs&lt;/span&gt;  &lt;span class="hljs-selector-tag"&gt;UIKit&lt;/span&gt;                             │
├──────────────────────┬──────────────────┬───────────────────────┤
│     &lt;span class="hljs-selector-tag"&gt;Feature&lt;/span&gt;          │    &lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt;       │       &lt;span class="hljs-selector-tag"&gt;UIKit&lt;/span&gt;            │
├──────────────────────┼──────────────────┼───────────────────────┤
│ &lt;span class="hljs-selector-tag"&gt;Paradigm&lt;/span&gt;             │ &lt;span class="hljs-selector-tag"&gt;Declarative&lt;/span&gt;      │ &lt;span class="hljs-selector-tag"&gt;Imperative&lt;/span&gt;             │
│ &lt;span class="hljs-selector-tag"&gt;Language&lt;/span&gt;             │ &lt;span class="hljs-selector-tag"&gt;Swift&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;only&lt;/span&gt;       │ &lt;span class="hljs-selector-tag"&gt;Swift&lt;/span&gt; / &lt;span class="hljs-selector-tag"&gt;Objective-C&lt;/span&gt;    │
│ &lt;span class="hljs-selector-tag"&gt;iOS&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Support&lt;/span&gt;          │ &lt;span class="hljs-selector-tag"&gt;iOS&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;13&lt;/span&gt;+          │ &lt;span class="hljs-selector-tag"&gt;iOS&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;2&lt;/span&gt;+                 │
│ &lt;span class="hljs-selector-tag"&gt;UI&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Tool&lt;/span&gt;              │ &lt;span class="hljs-selector-tag"&gt;Code&lt;/span&gt; / &lt;span class="hljs-selector-tag"&gt;Preview&lt;/span&gt;   │ &lt;span class="hljs-selector-tag"&gt;Storyboard&lt;/span&gt; / &lt;span class="hljs-selector-tag"&gt;Code&lt;/span&gt;      │
│ &lt;span class="hljs-selector-tag"&gt;State&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Mgmt&lt;/span&gt;           │ &lt;span class="hljs-selector-tag"&gt;Built-in&lt;/span&gt; (&lt;span class="hljs-variable"&gt;@State&lt;/span&gt;)│ &lt;span class="hljs-selector-tag"&gt;Manual&lt;/span&gt;                 │
│ &lt;span class="hljs-selector-tag"&gt;Layout&lt;/span&gt;               │ &lt;span class="hljs-selector-tag"&gt;Stacks&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;Grids&lt;/span&gt;    │ &lt;span class="hljs-selector-tag"&gt;Auto&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Layout&lt;/span&gt;            │
│ &lt;span class="hljs-selector-tag"&gt;Learning&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Curve&lt;/span&gt;       │ &lt;span class="hljs-selector-tag"&gt;Lower&lt;/span&gt; (modern)   │ &lt;span class="hljs-selector-tag"&gt;Higher&lt;/span&gt; (legacy)        │
│ &lt;span class="hljs-selector-tag"&gt;Maturity&lt;/span&gt;             │ &lt;span class="hljs-selector-tag"&gt;Growing&lt;/span&gt;          │ &lt;span class="hljs-selector-tag"&gt;Very&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Mature&lt;/span&gt;            │
│ &lt;span class="hljs-selector-tag"&gt;Animations&lt;/span&gt;           │ &lt;span class="hljs-selector-tag"&gt;Simple&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;modifiers&lt;/span&gt; │ &lt;span class="hljs-selector-tag"&gt;Complex&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;API&lt;/span&gt;            │
│ &lt;span class="hljs-selector-tag"&gt;Cross-Platform&lt;/span&gt;       │ &lt;span class="hljs-selector-tag"&gt;Yes&lt;/span&gt;              │ &lt;span class="hljs-selector-tag"&gt;iOS&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;only&lt;/span&gt;               │
└──────────────────────┴──────────────────┴───────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-when-to-choose-uikit-over-swiftui"&gt;⚠️ When to Choose UIKit Over SwiftUI&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Supporting iOS 12 or earlier&lt;/li&gt;
&lt;li&gt;Highly complex, performance-critical interfaces&lt;/li&gt;
&lt;li&gt;Using legacy Objective-C codebases&lt;/li&gt;
&lt;li&gt;Needing more fine-grained control over the render cycle&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id="3-declarative-vs-imperative-ui"&gt;3. Declarative vs Imperative UI&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is the difference between declarative and imperative UI programming?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;                    IMPERATIVE (UIKit)
    ┌────────────────────────────────────────────┐
    │  Step 1: &lt;span class="hljs-keyword"&gt;Create&lt;/span&gt; a UILabel                  │
    │  Step &lt;span class="hljs-number"&gt;2&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;Set&lt;/span&gt; &lt;span class="hljs-built_in"&gt;text&lt;/span&gt; = &lt;span class="hljs-string"&gt;"Hello"&lt;/span&gt;                │
    │  Step &lt;span class="hljs-number"&gt;3&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;Set&lt;/span&gt; font, color, frame            │
    │  Step &lt;span class="hljs-number"&gt;4&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;Add&lt;/span&gt; &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; &lt;span class="hljs-keyword"&gt;view&lt;/span&gt; &lt;span class="hljs-keyword"&gt;hierarchy&lt;/span&gt;             │
    │  Step &lt;span class="hljs-number"&gt;5&lt;/span&gt;: Manually &lt;span class="hljs-keyword"&gt;update&lt;/span&gt; &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; &lt;span class="hljs-keyword"&gt;data&lt;/span&gt; changes │
    │  Step &lt;span class="hljs-number"&gt;6&lt;/span&gt;: Manage lifecycle yourself         │
    └────────────────────────────────────────────┘
              ↓ &lt;span class="hljs-string"&gt;"Tell me HOW to do it"&lt;/span&gt;

                    DECLARATIVE (SwiftUI)
    ┌────────────────────────────────────────────┐
    │  &lt;span class="hljs-keyword"&gt;Describe&lt;/span&gt;: &lt;span class="hljs-string"&gt;"I want a bold Text saying      │
    │   'Hello', red foreground, large font."&lt;/span&gt;    │
    │                                            │
    │  SwiftUI handles rendering + updates       │
    │  automatically &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; &lt;span class="hljs-keyword"&gt;data&lt;/span&gt; changes           │
    └────────────────────────────────────────────┘
              ↓ &lt;span class="hljs-string"&gt;"Tell me WHAT you want"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;// ✅ SwiftUI — Declarative
Text(&lt;span class="hljs-string"&gt;"Hello, \(name)!"&lt;/span&gt;)
    .font(.title)
    .foregroundColor(.red)

// ❌ UIKit — Imperative equivalent
let &lt;span class="hljs-keyword"&gt;label&lt;/span&gt;&lt;span class="bash"&gt; = UILabel()
&lt;/span&gt;&lt;span class="hljs-keyword"&gt;label&lt;/span&gt;.&lt;span class="bash"&gt;text = &lt;span class="hljs-string"&gt;"Hello, \(name)!"&lt;/span&gt;
&lt;/span&gt;&lt;span class="hljs-keyword"&gt;label&lt;/span&gt;.&lt;span class="bash"&gt;font = UIFont.systemFont(ofSize: 24)
&lt;/span&gt;&lt;span class="hljs-keyword"&gt;label&lt;/span&gt;.&lt;span class="bash"&gt;textColor = .red
&lt;/span&gt;view.addSubview(&lt;span class="hljs-keyword"&gt;label&lt;/span&gt;&lt;span class="bash"&gt;)
&lt;/span&gt;// + Auto Layout constraints...
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="4-the-view-protocol"&gt;4. The View Protocol&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is the &lt;code&gt;View&lt;/code&gt; protocol in SwiftUI and why are views &lt;code&gt;struct&lt;/code&gt; types?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Every visible element in SwiftUI conforms to the &lt;code&gt;View&lt;/code&gt; protocol. It requires a single computed property:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;protocol View {
    associatedtype Body: View
    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: Self&lt;span class="hljs-selector-class"&gt;.Body&lt;/span&gt; { get }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="why-struct-value-type-instead-of-class-"&gt;Why Struct (Value Type) Instead of Class?&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────┐
│              Struct  vs  &lt;span class="hljs-keyword"&gt;Class&lt;/span&gt; &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; Views                  │
├──────────────────────┬───────────────────────────────────┤
│       Struct ✅       │          &lt;span class="hljs-keyword"&gt;Class&lt;/span&gt; ❌                 │
├──────────────────────┼───────────────────────────────────┤
│ Value &lt;span class="hljs-keyword"&gt;type&lt;/span&gt; (copied)  │ &lt;span class="hljs-keyword"&gt;Reference&lt;/span&gt; &lt;span class="hljs-keyword"&gt;type&lt;/span&gt; (shared)           │
│ No inheritance       │ Inheritance adds complexity       │
│ Thread-safe &lt;span class="hljs-keyword"&gt;by&lt;/span&gt; nature│ Needs manual synchronization      │
│ Lightweight          │ Heavier (heap allocation)         │
│ Immutable body       │ Mutable state = harder &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; reason  │
│ SwiftUI re-creates   │ Lifecycle management required     │
│ them cheaply         │                                   │
└──────────────────────┴───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; MyView: &lt;span class="hljs-built_in"&gt;View&lt;/span&gt; {
    var &lt;span class="hljs-built_in"&gt;title&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;String&lt;/span&gt;

    var body: some &lt;span class="hljs-built_in"&gt;View&lt;/span&gt; {
        Text(&lt;span class="hljs-built_in"&gt;title&lt;/span&gt;)
            .font(.headline)
            .padding()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="5-layout-system-vstack-hstack-zstack"&gt;5. Layout System: VStack, HStack, ZStack&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: Explain SwiftUI's layout containers.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────┐
│                 SwiftUI Layout Containers                 │
│                                                           │
│  VStack (Vertical)      HStack (Horizontal)              │
│  ┌──────────┐           ┌────────────────────┐           │
│  │  [&lt;span class="hljs-string"&gt;Item1&lt;/span&gt;] │           │ [&lt;span class="hljs-string"&gt;Item1&lt;/span&gt;][&lt;span class="hljs-symbol"&gt;Item2&lt;/span&gt;][&lt;span class="hljs-string"&gt;Item3&lt;/span&gt;] │         │
│  │  [Item2] │           └────────────────────┘           │
│  │  [Item3] │                                             │
│  └──────────┘           ZStack (Layered / Z-axis)        │
│                         ┌──────────────────┐             │
│                         │  Background      │             │
│                         │    ┌──────┐      │             │
│                         │    │ Text │      │             │
│                         │    └──────┘      │             │
│                         └──────────────────┘             │
└──────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// VStack — vertical arrangement&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;VStack&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;alignment&lt;/span&gt;: .leading, &lt;span class="hljs-attribute"&gt;spacing&lt;/span&gt;: &lt;span class="hljs-number"&gt;10&lt;/span&gt;) {
    &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Title"&lt;/span&gt;)&lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(.title)
    &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Subtitle"&lt;/span&gt;)&lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(.subheadline)
    &lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Tap Me"&lt;/span&gt;) { }
}

&lt;span class="hljs-comment"&gt;// HStack — horizontal arrangement&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;HStack&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;spacing&lt;/span&gt;: &lt;span class="hljs-number"&gt;16&lt;/span&gt;) {
    &lt;span class="hljs-selector-tag"&gt;Image&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;systemName&lt;/span&gt;: &lt;span class="hljs-string"&gt;"star.fill"&lt;/span&gt;)
    &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Favorites"&lt;/span&gt;)
    &lt;span class="hljs-selector-tag"&gt;Spacer&lt;/span&gt;()        &lt;span class="hljs-comment"&gt;// pushes content to edges&lt;/span&gt;
    &lt;span class="hljs-selector-tag"&gt;Badge&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;count&lt;/span&gt;: &lt;span class="hljs-number"&gt;3&lt;/span&gt;)
}

&lt;span class="hljs-comment"&gt;// ZStack — layer on top of each other&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;ZStack&lt;/span&gt; {
    &lt;span class="hljs-selector-tag"&gt;Color&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.blue&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.ignoresSafeArea&lt;/span&gt;()        &lt;span class="hljs-comment"&gt;// background layer&lt;/span&gt;
    &lt;span class="hljs-selector-tag"&gt;Image&lt;/span&gt;(&lt;span class="hljs-string"&gt;"banner"&lt;/span&gt;)                      &lt;span class="hljs-comment"&gt;// middle layer&lt;/span&gt;
    &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Overlay Text"&lt;/span&gt;)                 &lt;span class="hljs-comment"&gt;// top layer&lt;/span&gt;
        &lt;span class="hljs-selector-class"&gt;.foregroundColor&lt;/span&gt;(.white)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="lazy-variants-performance-"&gt;Lazy Variants (Performance)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;// &lt;span class="hljs-keyword"&gt;Use&lt;/span&gt; LazyVStack / LazyHStack &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; &lt;span class="hljs-keyword"&gt;large&lt;/span&gt; &lt;span class="hljs-keyword"&gt;data&lt;/span&gt; &lt;span class="hljs-keyword"&gt;sets&lt;/span&gt;
// They &lt;span class="hljs-keyword"&gt;only&lt;/span&gt; render views that &lt;span class="hljs-keyword"&gt;are&lt;/span&gt; currently &lt;span class="hljs-keyword"&gt;visible&lt;/span&gt;

ScrollView {
    LazyVStack {
        ForEach(&lt;span class="hljs-number"&gt;0.&lt;/span&gt;.&amp;lt;&lt;span class="hljs-number"&gt;1000&lt;/span&gt;) { &lt;span class="hljs-keyword"&gt;index&lt;/span&gt; &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
            &lt;span class="hljs-built_in"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Row \(index)"&lt;/span&gt;)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="6-state-management-state"&gt;6. State Management: @State&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is &lt;code&gt;@State&lt;/code&gt; and when should you use it?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;@State&lt;/code&gt; is a &lt;strong&gt;property wrapper&lt;/strong&gt; that lets SwiftUI manage a value locally within a single view. When the value changes, SwiftUI automatically re-renders the body.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;         &lt;span class="hljs-variable"&gt;@State&lt;/span&gt; Flow Diagram
    ┌─────────────────────────┐
    │       SwiftUI View       │
    │                          │
    │  &lt;span class="hljs-variable"&gt;@State&lt;/span&gt; var count = &lt;span class="hljs-number"&gt;0&lt;/span&gt;   │◄──── SwiftUI owns &amp;amp; manages
    │           │              │
    │           ▼              │
    │     body re-renders     │
    │     when count changes  │
    └─────────────────────────┘
              │
              ▼
    User taps button → count += &lt;span class="hljs-number"&gt;1&lt;/span&gt; → View updates
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;struct CounterView: View {
    @State private var count = &lt;span class="hljs-number"&gt;0&lt;/span&gt;      // &lt;span class="hljs-number"&gt;1&lt;/span&gt;. Declare &lt;span class="hljs-keyword"&gt;state&lt;/span&gt;

    var body: some View {
        VStack(spacing: &lt;span class="hljs-number"&gt;20&lt;/span&gt;) {
            Text(&lt;span class="hljs-string"&gt;"Count: \(count)"&lt;/span&gt;)   // &lt;span class="hljs-number"&gt;2&lt;/span&gt;. Read &lt;span class="hljs-keyword"&gt;state&lt;/span&gt;
                .font(.largeTitle)

            Button(&lt;span class="hljs-string"&gt;"Increment"&lt;/span&gt;) {
                count += &lt;span class="hljs-number"&gt;1&lt;/span&gt;            // &lt;span class="hljs-number"&gt;3&lt;/span&gt;. Mutate &lt;span class="hljs-keyword"&gt;state&lt;/span&gt; → auto re-render
            }
            .buttonStyle(.borderedProminent)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="-key-rules-for-state"&gt;&#128273; Key Rules for @State&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Always declare &lt;code&gt;@State&lt;/code&gt; as &lt;code&gt;private&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Only use inside the view that &lt;strong&gt;owns&lt;/strong&gt; the data&lt;/li&gt;
&lt;li&gt;For sharing across views → use &lt;code&gt;@Binding&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;For complex objects → use &lt;code&gt;@StateObject&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id="7-binding"&gt;7. @Binding&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is &lt;code&gt;@Binding&lt;/code&gt; and how does it differ from &lt;code&gt;@State&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;@Binding&lt;/code&gt; creates a &lt;strong&gt;two-way connection&lt;/strong&gt; between a parent view's state and a child view. The child can read and write the value without owning it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;       &lt;span class="hljs-variable"&gt;@State&lt;/span&gt; / &lt;span class="hljs-variable"&gt;@Binding&lt;/span&gt; Relationship

    Parent View                   Child View
    ┌──────────────────┐         ┌──────────────────┐
    │ &lt;span class="hljs-variable"&gt;@State&lt;/span&gt; var       │         │ &lt;span class="hljs-variable"&gt;@Binding&lt;/span&gt; var      │
    │  isOn = false    │────────►│  &lt;span class="hljs-attribute"&gt;isOn&lt;/span&gt;: Bool       │
    │                  │◄────────│                   │
    │  (owns the data) │  sync   │  (references data)│
    └──────────────────┘         └──────────────────┘
            │                             │
            └─────── Both update ─────────┘
                  the same source of truth
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Parent — owns the state&lt;/span&gt;
struct ParentView: View {
    @State private &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; isToggled = false

    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: some View {
        ToggleView(isOn: &lt;span class="hljs-variable"&gt;$isToggled&lt;/span&gt;)    &lt;span class="hljs-comment"&gt;// $ creates a Binding&lt;/span&gt;
    }
}

&lt;span class="hljs-comment"&gt;// Child — receives a binding&lt;/span&gt;
struct ToggleView: View {
    @Binding &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; isOn: Bool             &lt;span class="hljs-comment"&gt;// Does NOT own the data&lt;/span&gt;

    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: some View {
        Toggle(&lt;span class="hljs-string"&gt;"Enable Feature"&lt;/span&gt;, isOn: &lt;span class="hljs-variable"&gt;$isOn&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="8-observedobject-stateobject"&gt;8. @ObservedObject &amp;amp; @StateObject&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is the difference between &lt;code&gt;@StateObject&lt;/code&gt; and &lt;code&gt;@ObservedObject&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Both work with &lt;code&gt;ObservableObject&lt;/code&gt; classes, but differ in &lt;strong&gt;ownership and lifecycle&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│           &lt;span class="hljs-variable"&gt;@StateObject&lt;/span&gt;  vs  &lt;span class="hljs-variable"&gt;@ObservedObject&lt;/span&gt;                  │
├──────────────────────────┬──────────────────────────────────┤
│      &lt;span class="hljs-variable"&gt;@StateObject&lt;/span&gt; ✅      │      &lt;span class="hljs-variable"&gt;@ObservedObject&lt;/span&gt;             │
├──────────────────────────┼──────────────────────────────────┤
│ VIEW creates the object  │ Object injected from outside      │
│ VIEW owns the object     │ View does NOT own it              │
│ Persists across re-draws │ May be re-created on re-draw      │
│ Use in CREATING view     │ Use in RECEIVING view             │
│                          │                                   │
│ &lt;span class="hljs-variable"&gt;@StateObject&lt;/span&gt; var vm =    │ &lt;span class="hljs-variable"&gt;@ObservedObject&lt;/span&gt; var &lt;span class="hljs-attribute"&gt;vm&lt;/span&gt;:           │
│   ViewModel()            │   ViewModel                       │
└──────────────────────────┴──────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Observable class&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;UserViewModel&lt;/span&gt;: &lt;span class="hljs-title"&gt;ObservableObject&lt;/span&gt; &lt;/span&gt;{
    @&lt;span class="hljs-type"&gt;Published&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; username = &lt;span class="hljs-string"&gt;"John"&lt;/span&gt;
    @&lt;span class="hljs-type"&gt;Published&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; score = &lt;span class="hljs-number"&gt;0&lt;/span&gt;

    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;incrementScore&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        score += &lt;span class="hljs-number"&gt;1&lt;/span&gt;
    }
}

&lt;span class="hljs-comment"&gt;// ✅ Use @StateObject in the view that CREATES the object&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;ProfileView&lt;/span&gt;: &lt;span class="hljs-title"&gt;View&lt;/span&gt; &lt;/span&gt;{
    @&lt;span class="hljs-type"&gt;StateObject&lt;/span&gt; &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; viewModel = &lt;span class="hljs-type"&gt;UserViewModel&lt;/span&gt;()

    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; body: some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
        &lt;span class="hljs-type"&gt;VStack&lt;/span&gt; {
            &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"User: &lt;span class="hljs-subst"&gt;\(viewModel.username)&lt;/span&gt;"&lt;/span&gt;)
            &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Score: &lt;span class="hljs-subst"&gt;\(viewModel.score)&lt;/span&gt;"&lt;/span&gt;)
            &lt;span class="hljs-type"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Add Score"&lt;/span&gt;) { viewModel.incrementScore() }
            &lt;span class="hljs-type"&gt;ScoreBoard&lt;/span&gt;(viewModel: viewModel)   &lt;span class="hljs-comment"&gt;// pass down&lt;/span&gt;
        }
    }
}

&lt;span class="hljs-comment"&gt;// ✅ Use @ObservedObject in views that RECEIVE the object&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;ScoreBoard&lt;/span&gt;: &lt;span class="hljs-title"&gt;View&lt;/span&gt; &lt;/span&gt;{
    @&lt;span class="hljs-type"&gt;ObservedObject&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; viewModel: &lt;span class="hljs-type"&gt;UserViewModel&lt;/span&gt;

    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; body: some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
        &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Current Score: &lt;span class="hljs-subst"&gt;\(viewModel.score)&lt;/span&gt;"&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="9-environmentobject"&gt;9. @EnvironmentObject&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is &lt;code&gt;@EnvironmentObject&lt;/code&gt; and when should you use it?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;@EnvironmentObject&lt;/code&gt; allows you to &lt;strong&gt;share data across many views&lt;/strong&gt; in the hierarchy without passing it explicitly through each child.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;         @EnvironmentObject — &lt;span class="hljs-keyword"&gt;Shared&lt;/span&gt; Data Across Tree

              App Level
           ┌──────────────┐
           │  AppState    │  ◄── injected &lt;span class="hljs-keyword"&gt;with&lt;/span&gt; .environmentObject()
           └──────┬───────┘
                  │ available &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; &lt;span class="hljs-keyword"&gt;ALL&lt;/span&gt; descendants
        ┌─────────▼──────────┐
        │    HomeView        │
        └───────┬────────────┘
         ┌──────▼──────┐
         │  SettingsView│  ← can &lt;span class="hljs-keyword"&gt;access&lt;/span&gt; AppState directly
         └─────┬────────┘
               │
         ┌─────▼────────┐
         │  UserProfile │  ← can also &lt;span class="hljs-keyword"&gt;access&lt;/span&gt; AppState directly
         └──────────────┘
         No need &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; pass through each level! ✅
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// 1. Define the shared model&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;class&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;AppState&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;ObservableObject&lt;/span&gt; {
    &lt;span class="hljs-variable"&gt;@Published&lt;/span&gt; var isLoggedIn = false
    &lt;span class="hljs-variable"&gt;@Published&lt;/span&gt; var currentUser = &lt;span class="hljs-string"&gt;""&lt;/span&gt;
}

&lt;span class="hljs-comment"&gt;// 2. Inject at the root&lt;/span&gt;
&lt;span class="hljs-variable"&gt;@main&lt;/span&gt;
struct &lt;span class="hljs-attribute"&gt;MyApp&lt;/span&gt;: App {
    &lt;span class="hljs-variable"&gt;@StateObject&lt;/span&gt; var appState = AppState()

    var &lt;span class="hljs-attribute"&gt;body&lt;/span&gt;: some Scene {
        &lt;span class="hljs-selector-tag"&gt;WindowGroup&lt;/span&gt; {
            &lt;span class="hljs-selector-tag"&gt;ContentView&lt;/span&gt;()
                &lt;span class="hljs-selector-class"&gt;.environmentObject&lt;/span&gt;(appState)   &lt;span class="hljs-comment"&gt;// inject here&lt;/span&gt;
        }
    }
}

&lt;span class="hljs-comment"&gt;// 3. Use anywhere in the hierarchy&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;struct&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;ProfileView&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;View&lt;/span&gt; {
    &lt;span class="hljs-variable"&gt;@EnvironmentObject&lt;/span&gt; var &lt;span class="hljs-attribute"&gt;appState&lt;/span&gt;: AppState  &lt;span class="hljs-comment"&gt;// no passing needed&lt;/span&gt;

    var &lt;span class="hljs-attribute"&gt;body&lt;/span&gt;: some View {
        &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Hello, \(appState.currentUser)"&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="10-data-flow-architecture"&gt;10. Data Flow Architecture&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How does data flow work in SwiftUI?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;              &lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Data&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Flow&lt;/span&gt; — &lt;span class="hljs-selector-tag"&gt;Unidirectional&lt;/span&gt;

    ┌──────────────────────────────────────────────┐
    │                                              │
    │   &lt;span class="hljs-selector-tag"&gt;User&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Action&lt;/span&gt; (tap, swipe, input)            │
    │          │                                   │
    │          ▼                                   │
    │   &lt;span class="hljs-selector-tag"&gt;State&lt;/span&gt;/&lt;span class="hljs-selector-tag"&gt;Model&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Changes&lt;/span&gt;                        │
    │  (&lt;span class="hljs-variable"&gt;@State&lt;/span&gt;, &lt;span class="hljs-variable"&gt;@Published&lt;/span&gt;, etc.)                  │
    │          │                                   │
    │          ▼                                   │
    │   &lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;detects&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;change&lt;/span&gt;                     │
    │          │                                   │
    │          ▼                                   │
    │   &lt;span class="hljs-selector-tag"&gt;View&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;re-evaluated&lt;/span&gt;                     │
    │          │                                   │
    │          ▼                                   │
    │   &lt;span class="hljs-selector-tag"&gt;Diff&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;computed&lt;/span&gt; (minimal updates)            │
    │          │                                   │
    │          ▼                                   │
    │   &lt;span class="hljs-selector-tag"&gt;UI&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Updated&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;on&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;screen&lt;/span&gt;                       │
    │          │                                   │
    │          └────────────────────────────────── │
    │                     ↑ &lt;span class="hljs-selector-tag"&gt;cycle&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;repeats&lt;/span&gt;           │
    └──────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;h2 id="11-property-wrappers-comparison"&gt;11. Property Wrappers Comparison&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: Can you summarize all SwiftUI property wrappers?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────────┐
│               &lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Property&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Wrappers&lt;/span&gt; — &lt;span class="hljs-selector-tag"&gt;Quick&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Reference&lt;/span&gt;             │
├────────────────────┬─────────────────────────┬───────────────────────┤
│   &lt;span class="hljs-selector-tag"&gt;Wrapper&lt;/span&gt;          │      &lt;span class="hljs-selector-tag"&gt;Purpose&lt;/span&gt;             │     &lt;span class="hljs-selector-tag"&gt;Use&lt;/span&gt; &lt;span class="hljs-keyword"&gt;When&lt;/span&gt;          │
├────────────────────┼─────────────────────────┼───────────────────────┤
│ &lt;span class="hljs-variable"&gt;@State&lt;/span&gt;             │ Local value storage      │ Simple local UI state │
│ &lt;span class="hljs-variable"&gt;@Binding&lt;/span&gt;           │ Two-way reference        │ Pass state to child   │
│ &lt;span class="hljs-variable"&gt;@StateObject&lt;/span&gt;       │ Owns ObservableObject    │ Creating a VM in view │
│ &lt;span class="hljs-variable"&gt;@ObservedObject&lt;/span&gt;    │ References Observable    │ Receiving a VM        │
│ &lt;span class="hljs-variable"&gt;@EnvironmentObject&lt;/span&gt; │ Shared across hierarchy  │ App-wide shared data  │
│ &lt;span class="hljs-variable"&gt;@Environment&lt;/span&gt;       │ System values            │ colorScheme, locale   │
│ &lt;span class="hljs-variable"&gt;@Published&lt;/span&gt;         │ Observable property      │ Inside ObservableObj  │
│ &lt;span class="hljs-variable"&gt;@AppStorage&lt;/span&gt;        │ UserDefaults binding     │ Persist user prefs    │
│ &lt;span class="hljs-variable"&gt;@SceneStorage&lt;/span&gt;      │ Scene-specific storage   │ Per-scene state       │
│ &lt;span class="hljs-variable"&gt;@FetchRequest&lt;/span&gt;      │ CoreData query           │ CoreData integration  │
└────────────────────┴─────────────────────────┴───────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// @Environment — reading system values&lt;/span&gt;
struct ThemeAwareView: View {
    @Environment(\.colorScheme) &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; colorScheme

    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: some View {
        Text(&lt;span class="hljs-string"&gt;"Mode: \(colorScheme == .dark ? "&lt;/span&gt;Dark&lt;span class="hljs-string"&gt;" : "&lt;/span&gt;Light&lt;span class="hljs-string"&gt;")"&lt;/span&gt;)
    }
}

&lt;span class="hljs-comment"&gt;// @AppStorage — UserDefaults made easy&lt;/span&gt;
struct SettingsView: View {
    @AppStorage(&lt;span class="hljs-string"&gt;"isDarkMode"&lt;/span&gt;) &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; isDarkMode = false

    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: some View {
        Toggle(&lt;span class="hljs-string"&gt;"Dark Mode"&lt;/span&gt;, isOn: &lt;span class="hljs-variable"&gt;$isDarkMode&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="12-animations-in-swiftui"&gt;12. Animations in SwiftUI&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How do you implement animations in SwiftUI?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SwiftUI supports two styles of animation: &lt;strong&gt;implicit&lt;/strong&gt; and &lt;strong&gt;explicit&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        &lt;span class="hljs-keyword"&gt;Implicit&lt;/span&gt; Animation
        ─────────────────
        Attach .animation() to a view.
        &lt;span class="hljs-built_in"&gt;Any&lt;/span&gt; state change affecting that view is animated.

        Explicit Animation
        ──────────────────
        Wrap state change &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; withAnimation { }.
        &lt;span class="hljs-keyword"&gt;Only&lt;/span&gt; that specific change is animated.
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Implicit Animation&lt;/span&gt;
struct &lt;span class="hljs-string"&gt;ImplicitAnimationView:&lt;/span&gt; View {
    &lt;span class="hljs-meta"&gt;@State&lt;/span&gt; &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; var scale = &lt;span class="hljs-number"&gt;1.0&lt;/span&gt;

    var &lt;span class="hljs-string"&gt;body:&lt;/span&gt; some View {
        Circle()
            .frame(&lt;span class="hljs-string"&gt;width:&lt;/span&gt; &lt;span class="hljs-number"&gt;100&lt;/span&gt;, &lt;span class="hljs-string"&gt;height:&lt;/span&gt; &lt;span class="hljs-number"&gt;100&lt;/span&gt;)
            .scaleEffect(scale)
            .animation(.spring(&lt;span class="hljs-string"&gt;response:&lt;/span&gt; &lt;span class="hljs-number"&gt;0.5&lt;/span&gt;, &lt;span class="hljs-string"&gt;dampingFraction:&lt;/span&gt; &lt;span class="hljs-number"&gt;0.6&lt;/span&gt;), &lt;span class="hljs-string"&gt;value:&lt;/span&gt; scale)
            .onTapGesture { scale = scale == &lt;span class="hljs-number"&gt;1.0&lt;/span&gt; ? 1.5 : &lt;span class="hljs-number"&gt;1.0&lt;/span&gt; }
    }
}

&lt;span class="hljs-comment"&gt;// Explicit Animation&lt;/span&gt;
struct &lt;span class="hljs-string"&gt;ExplicitAnimationView:&lt;/span&gt; View {
    &lt;span class="hljs-meta"&gt;@State&lt;/span&gt; &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; var isExpanded = &lt;span class="hljs-literal"&gt;false&lt;/span&gt;

    var &lt;span class="hljs-string"&gt;body:&lt;/span&gt; some View {
        VStack {
            Rectangle()
                .frame(&lt;span class="hljs-string"&gt;width:&lt;/span&gt; isExpanded ? 300 : &lt;span class="hljs-number"&gt;100&lt;/span&gt;,
&lt;span class="hljs-symbol"&gt;                       height:&lt;/span&gt; isExpanded ? 300 : &lt;span class="hljs-number"&gt;100&lt;/span&gt;)

            Button(&lt;span class="hljs-string"&gt;"Toggle"&lt;/span&gt;) {
                withAnimation(.easeInOut(&lt;span class="hljs-string"&gt;duration:&lt;/span&gt; &lt;span class="hljs-number"&gt;0.4&lt;/span&gt;)) {
                    isExpanded.toggle()   &lt;span class="hljs-comment"&gt;// only this change animates&lt;/span&gt;
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="animation-types"&gt;Animation Types&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────────────┐
│          SwiftUI Animation Curves            │
├──────────────────┬───────────────────────────┤
│ &lt;span class="hljs-selector-class"&gt;.linear&lt;/span&gt;          │ Constant speed             │
│ &lt;span class="hljs-selector-class"&gt;.easeIn&lt;/span&gt;          │ Starts slow, ends fast     │
│ &lt;span class="hljs-selector-class"&gt;.easeOut&lt;/span&gt;         │ Starts fast, ends slow     │
│ &lt;span class="hljs-selector-class"&gt;.easeInOut&lt;/span&gt;       │ Slow → fast → slow         │
│ .spring(...)     │ Bouncy, natural feel        │
│ &lt;span class="hljs-selector-class"&gt;.interpolating&lt;/span&gt;   │ Custom timing curve         │
│   SpringAnim     │                            │
└──────────────────┴───────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="transitions-for-appearing-disappearing-views-"&gt;Transitions (for appearing/disappearing views)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;if&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;isVisible&lt;/span&gt; {
    &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Hello!"&lt;/span&gt;)
        &lt;span class="hljs-selector-class"&gt;.transition&lt;/span&gt;(.asymmetric(
            &lt;span class="hljs-attribute"&gt;insertion&lt;/span&gt;: .slide,
            &lt;span class="hljs-attribute"&gt;removal&lt;/span&gt;: .opacity
        ))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="13-navigationview-navigationstack"&gt;13. NavigationView &amp;amp; NavigationStack&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How does navigation work in SwiftUI? What is NavigationStack?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;     &lt;span class="hljs-selector-tag"&gt;NavigationStack&lt;/span&gt; (iOS &lt;span class="hljs-number"&gt;16&lt;/span&gt;+)   ← &lt;span class="hljs-selector-tag"&gt;Preferred&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;modern&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;approach&lt;/span&gt;
     ┌──────────────────────────────────────────┐
     │  &lt;span class="hljs-selector-tag"&gt;NavigationStack&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;path&lt;/span&gt;: $navPath) {       │
     │    &lt;span class="hljs-selector-tag"&gt;ContentView&lt;/span&gt;()                          │
     │      &lt;span class="hljs-selector-class"&gt;.navigationDestination&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;for&lt;/span&gt;: ...) {} │
     │  }                                        │
     └──────────────────────────────────────────┘
                      │
                      ▼
     &lt;span class="hljs-selector-tag"&gt;Push&lt;/span&gt; → &lt;span class="hljs-selector-attr"&gt;[Root]&lt;/span&gt; → &lt;span class="hljs-selector-attr"&gt;[Detail]&lt;/span&gt; → &lt;span class="hljs-selector-attr"&gt;[SubDetail]&lt;/span&gt;
     &lt;span class="hljs-selector-tag"&gt;Pop&lt;/span&gt;  ← &lt;span class="hljs-selector-attr"&gt;[Root]&lt;/span&gt; ← &lt;span class="hljs-selector-attr"&gt;[Detail]&lt;/span&gt; ← &lt;span class="hljs-selector-attr"&gt;[SubDetail]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Modern Navigation (iOS 16+)&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;struct&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;AppNavigationView&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;View&lt;/span&gt; {
    &lt;span class="hljs-variable"&gt;@State&lt;/span&gt; private var path = NavigationPath()

    var &lt;span class="hljs-attribute"&gt;body&lt;/span&gt;: some View {
        &lt;span class="hljs-selector-tag"&gt;NavigationStack&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;path&lt;/span&gt;: $path) {
            &lt;span class="hljs-selector-tag"&gt;List&lt;/span&gt;(items) { &lt;span class="hljs-selector-tag"&gt;item&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;in&lt;/span&gt;
                &lt;span class="hljs-selector-tag"&gt;NavigationLink&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;value&lt;/span&gt;: item) {
                    &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(item.name)
                }
            }
            &lt;span class="hljs-selector-class"&gt;.navigationTitle&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Items"&lt;/span&gt;)
            &lt;span class="hljs-selector-class"&gt;.navigationDestination&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;for&lt;/span&gt;: Item.self) { &lt;span class="hljs-selector-tag"&gt;item&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;in&lt;/span&gt;
                &lt;span class="hljs-selector-tag"&gt;ItemDetailView&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;item&lt;/span&gt;: item)
            }
        }
    }
}

&lt;span class="hljs-comment"&gt;// Programmatic Navigation&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Go to Detail"&lt;/span&gt;) {
    &lt;span class="hljs-selector-tag"&gt;path&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.append&lt;/span&gt;(selectedItem)   &lt;span class="hljs-comment"&gt;// push&lt;/span&gt;
}

&lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Go Back"&lt;/span&gt;) {
    &lt;span class="hljs-selector-tag"&gt;path&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.removeLast&lt;/span&gt;()           &lt;span class="hljs-comment"&gt;// pop&lt;/span&gt;
}

&lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Go to Root"&lt;/span&gt;) {
    &lt;span class="hljs-selector-tag"&gt;path&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.removeLast&lt;/span&gt;(path.count) &lt;span class="hljs-comment"&gt;// pop all&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="14-list-foreach"&gt;14. List &amp;amp; ForEach&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is the difference between &lt;code&gt;List&lt;/code&gt; and &lt;code&gt;ForEach&lt;/code&gt; in SwiftUI?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────────────────────────────────┐
│           &lt;span class="hljs-keyword"&gt;List&lt;/span&gt;  vs  &lt;span class="hljs-keyword"&gt;ForEach&lt;/span&gt;                    │
├───────────────────────┬────────────────────────┤
│         &lt;span class="hljs-keyword"&gt;List&lt;/span&gt;          │       &lt;span class="hljs-keyword"&gt;ForEach&lt;/span&gt;          │
├───────────────────────┼────────────────────────┤
│ Full scroll container │ Just iterates views    │
│ Provides separators   │ &lt;span class="hljs-keyword"&gt;No&lt;/span&gt; built-&lt;span class="hljs-keyword"&gt;in&lt;/span&gt; styling    │
│ Built-&lt;span class="hljs-keyword"&gt;in&lt;/span&gt; swipe-delete │ Used inside containers │
│ Selection support     │ &lt;span class="hljs-keyword"&gt;More&lt;/span&gt; flexible          │
│ Auto cell styling     │ Pure &lt;span class="hljs-keyword"&gt;view&lt;/span&gt; builder      │
└───────────────────────┴────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;struct FruitListView: View {
    @State private &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; fruits = [&lt;span class="hljs-string"&gt;"Apple"&lt;/span&gt;, &lt;span class="hljs-string"&gt;"Banana"&lt;/span&gt;, &lt;span class="hljs-string"&gt;"Cherry"&lt;/span&gt;]

    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: some View {
        List {
            ForEach(fruits, id: \.self) { fruit &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
                Text(fruit)
            }
            &lt;span class="hljs-selector-class"&gt;.onDelete&lt;/span&gt; { indexSet &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
                fruits.remove(atOffsets: indexSet)
            }
            &lt;span class="hljs-selector-class"&gt;.onMove&lt;/span&gt; { from, to &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
                fruits.move(fromOffsets: from, toOffset: to)
            }
        }
        &lt;span class="hljs-selector-class"&gt;.toolbar&lt;/span&gt; {
            EditButton()
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="identifiable-protocol"&gt;Identifiable Protocol&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;// ✅ Always &lt;span class="hljs-keyword"&gt;use&lt;/span&gt; Identifiable &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; proper diffing
&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; Product: Identifiable {
    let &lt;span class="hljs-keyword"&gt;id&lt;/span&gt; = &lt;span class="hljs-keyword"&gt;UUID&lt;/span&gt;()
    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; &lt;span class="hljs-keyword"&gt;name&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;String&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; price: &lt;span class="hljs-keyword"&gt;Double&lt;/span&gt;
}

&lt;span class="hljs-keyword"&gt;List&lt;/span&gt;(products) { product &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
    ProductRow(product: product)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="15-view-modifiers"&gt;15. View Modifiers&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What are view modifiers and how do they work?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Modifiers return a &lt;strong&gt;new modified view&lt;/strong&gt; — they don't mutate the original. Order matters!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        Modifier Chain — Order Matters!

  Text(&lt;span class="hljs-string"&gt;"Hello"&lt;/span&gt;)
       │
       ▼
  .padding()        → adds padding around &lt;span class="hljs-built_in"&gt;text&lt;/span&gt;
       │
       ▼
  .&lt;span class="hljs-built_in"&gt;background&lt;/span&gt;(.&lt;span class="hljs-built_in"&gt;blue&lt;/span&gt;) → &lt;span class="hljs-built_in"&gt;blue&lt;/span&gt; covers the padded area
       │
       ▼
  .cornerRadius(&lt;span class="hljs-number"&gt;10&lt;/span&gt;)  → rounds the &lt;span class="hljs-built_in"&gt;blue&lt;/span&gt; &lt;span class="hljs-built_in"&gt;background&lt;/span&gt;

  vs.

  Text(&lt;span class="hljs-string"&gt;"Hello"&lt;/span&gt;)
  .&lt;span class="hljs-built_in"&gt;background&lt;/span&gt;(.&lt;span class="hljs-built_in"&gt;blue&lt;/span&gt;) → &lt;span class="hljs-built_in"&gt;blue&lt;/span&gt; only behind the &lt;span class="hljs-built_in"&gt;text&lt;/span&gt; (no padding)
  .padding()         → padding outside the &lt;span class="hljs-built_in"&gt;blue&lt;/span&gt; &lt;span class="hljs-built_in"&gt;box&lt;/span&gt;
  .cornerRadius(&lt;span class="hljs-number"&gt;10&lt;/span&gt;)  → rounds nothing visible here
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;("&lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt;")
    &lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(&lt;span class="hljs-selector-class"&gt;.title&lt;/span&gt;)
    &lt;span class="hljs-selector-class"&gt;.fontWeight&lt;/span&gt;(&lt;span class="hljs-selector-class"&gt;.bold&lt;/span&gt;)
    &lt;span class="hljs-selector-class"&gt;.foregroundColor&lt;/span&gt;(&lt;span class="hljs-selector-class"&gt;.white&lt;/span&gt;)
    &lt;span class="hljs-selector-class"&gt;.padding&lt;/span&gt;(&lt;span class="hljs-selector-class"&gt;.horizontal&lt;/span&gt;, 20)
    &lt;span class="hljs-selector-class"&gt;.padding&lt;/span&gt;(&lt;span class="hljs-selector-class"&gt;.vertical&lt;/span&gt;, 10)
    &lt;span class="hljs-selector-class"&gt;.background&lt;/span&gt;(&lt;span class="hljs-selector-tag"&gt;Color&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.blue&lt;/span&gt;)
    &lt;span class="hljs-selector-class"&gt;.clipShape&lt;/span&gt;(&lt;span class="hljs-selector-tag"&gt;RoundedRectangle&lt;/span&gt;(&lt;span class="hljs-selector-tag"&gt;cornerRadius&lt;/span&gt;: 12))
    &lt;span class="hljs-selector-class"&gt;.shadow&lt;/span&gt;(&lt;span class="hljs-selector-tag"&gt;color&lt;/span&gt;: &lt;span class="hljs-selector-class"&gt;.black&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.opacity&lt;/span&gt;(0&lt;span class="hljs-selector-class"&gt;.3&lt;/span&gt;), &lt;span class="hljs-selector-tag"&gt;radius&lt;/span&gt;: 8, &lt;span class="hljs-selector-tag"&gt;x&lt;/span&gt;: 0, &lt;span class="hljs-selector-tag"&gt;y&lt;/span&gt;: 4)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="16-custom-viewmodifier"&gt;16. Custom ViewModifier&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How do you create a reusable custom ViewModifier?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// 1. Define the modifier&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;CardStyle&lt;/span&gt;: &lt;span class="hljs-title"&gt;ViewModifier&lt;/span&gt; &lt;/span&gt;{
    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; backgroundColor: &lt;span class="hljs-type"&gt;Color&lt;/span&gt; = .white

    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;body&lt;/span&gt;&lt;span class="hljs-params"&gt;(content: Content)&lt;/span&gt;&lt;/span&gt; -&amp;gt; some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
        content
            .padding()
            .background(backgroundColor)
            .cornerRadius(&lt;span class="hljs-number"&gt;12&lt;/span&gt;)
            .shadow(color: .black.opacity(&lt;span class="hljs-number"&gt;0.1&lt;/span&gt;), radius: &lt;span class="hljs-number"&gt;6&lt;/span&gt;, x: &lt;span class="hljs-number"&gt;0&lt;/span&gt;, y: &lt;span class="hljs-number"&gt;3&lt;/span&gt;)
    }
}

&lt;span class="hljs-comment"&gt;// 2. Add a View extension for clean syntax&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;extension&lt;/span&gt; &lt;span class="hljs-title"&gt;View&lt;/span&gt; &lt;/span&gt;{
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;cardStyle&lt;/span&gt;&lt;span class="hljs-params"&gt;(background: Color = .white)&lt;/span&gt;&lt;/span&gt; -&amp;gt; some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
        modifier(&lt;span class="hljs-type"&gt;CardStyle&lt;/span&gt;(backgroundColor: background))
    }
}

&lt;span class="hljs-comment"&gt;// 3. Use it anywhere&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;SomeView&lt;/span&gt;: &lt;span class="hljs-title"&gt;View&lt;/span&gt; &lt;/span&gt;{
    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; body: some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
        &lt;span class="hljs-type"&gt;VStack&lt;/span&gt; {
            &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Card Title"&lt;/span&gt;).font(.headline)
            &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Card subtitle goes here"&lt;/span&gt;)
        }
        .cardStyle(background: .white)   &lt;span class="hljs-comment"&gt;// ✅ Clean reusable modifier&lt;/span&gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="17-viewbuilder"&gt;17. @ViewBuilder&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is &lt;code&gt;@ViewBuilder&lt;/code&gt; and when do you use it?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;@ViewBuilder&lt;/code&gt; is a &lt;strong&gt;result builder&lt;/strong&gt; that lets functions return multiple views from a single closure — the same mechanism SwiftUI itself uses for &lt;code&gt;body&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Without @ViewBuilder — can only return ONE view&lt;/span&gt;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;simpleHeader&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; -&amp;gt; some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
    &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Title"&lt;/span&gt;)  &lt;span class="hljs-comment"&gt;// must be a single view&lt;/span&gt;
}

&lt;span class="hljs-comment"&gt;// With @ViewBuilder — can return MULTIPLE views conditionally&lt;/span&gt;
@&lt;span class="hljs-type"&gt;ViewBuilder&lt;/span&gt;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;dynamicContent&lt;/span&gt;&lt;span class="hljs-params"&gt;(isLoggedIn: Bool)&lt;/span&gt;&lt;/span&gt; -&amp;gt; some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; isLoggedIn {
        &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Welcome Back!"&lt;/span&gt;)          &lt;span class="hljs-comment"&gt;// ← multiple views based on condition&lt;/span&gt;
        &lt;span class="hljs-type"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Logout"&lt;/span&gt;) { }
    } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
        &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Please Log In"&lt;/span&gt;)
        &lt;span class="hljs-type"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Login"&lt;/span&gt;) { }
    }
}

&lt;span class="hljs-comment"&gt;// Custom container using @ViewBuilder&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;Card&lt;/span&gt;&amp;lt;&lt;span class="hljs-title"&gt;Content&lt;/span&gt;: &lt;span class="hljs-title"&gt;View&lt;/span&gt;&amp;gt;: &lt;span class="hljs-title"&gt;View&lt;/span&gt; &lt;/span&gt;{
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; title: &lt;span class="hljs-type"&gt;String&lt;/span&gt;
    @&lt;span class="hljs-type"&gt;ViewBuilder&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; content: () -&amp;gt; &lt;span class="hljs-type"&gt;Content&lt;/span&gt;   &lt;span class="hljs-comment"&gt;// accepts view builder closure&lt;/span&gt;

    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; body: some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
        &lt;span class="hljs-type"&gt;VStack&lt;/span&gt;(alignment: .leading) {
            &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(title).font(.headline)
            &lt;span class="hljs-type"&gt;Divider&lt;/span&gt;()
            content()                          &lt;span class="hljs-comment"&gt;// renders whatever is passed&lt;/span&gt;
        }
        .padding()
        .background(.white)
        .cornerRadius(&lt;span class="hljs-number"&gt;10&lt;/span&gt;)
    }
}

&lt;span class="hljs-comment"&gt;// Usage&lt;/span&gt;
&lt;span class="hljs-type"&gt;Card&lt;/span&gt;(title: &lt;span class="hljs-string"&gt;"Profile"&lt;/span&gt;) {
    &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Name: John"&lt;/span&gt;)
    &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Age: 30"&lt;/span&gt;)
    &lt;span class="hljs-type"&gt;Image&lt;/span&gt;(systemName: &lt;span class="hljs-string"&gt;"person.circle"&lt;/span&gt;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="18-geometryreader"&gt;18. GeometryReader&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What is &lt;code&gt;GeometryReader&lt;/code&gt; and when should you use it?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;GeometryReader&lt;/code&gt; gives you access to the &lt;strong&gt;size and coordinate space&lt;/strong&gt; of the parent container, enabling responsive and proportional layouts.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    GeometryReader Concept:
    ┌──────────────────────────────────────────┐
    │         Parent Container                  │
    │                                           │
    │   GeometryReader { geometry &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;            │
    │     ┌──────────────────────────────┐      │
    │     │ geometry&lt;span class="hljs-selector-class"&gt;.size&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.width&lt;/span&gt;  = &lt;span class="hljs-number"&gt;375&lt;/span&gt;   │      │
    │     │ geometry&lt;span class="hljs-selector-class"&gt;.size&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.height&lt;/span&gt; = &lt;span class="hljs-number"&gt;800&lt;/span&gt;   │      │
    │     │ geometry.frame(&lt;span class="hljs-keyword"&gt;in&lt;/span&gt;: .local)   │      │
    │     │ geometry.frame(&lt;span class="hljs-keyword"&gt;in&lt;/span&gt;: .global)  │      │
    │     └──────────────────────────────┘      │
    │                                           │
    └──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; ResponsiveView: View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                &lt;span class="hljs-comment"&gt;// 60% width, 30% height of the available space&lt;/span&gt;
                Rectangle()
                    .&lt;span class="hljs-built_in"&gt;fill&lt;/span&gt;(Color.blue)
                    .frame(
                        &lt;span class="hljs-built_in"&gt;width&lt;/span&gt;: geometry.&lt;span class="hljs-built_in"&gt;size&lt;/span&gt;.&lt;span class="hljs-built_in"&gt;width&lt;/span&gt; * &lt;span class="hljs-number"&gt;0.6&lt;/span&gt;,
                        &lt;span class="hljs-built_in"&gt;height&lt;/span&gt;: geometry.&lt;span class="hljs-built_in"&gt;size&lt;/span&gt;.&lt;span class="hljs-built_in"&gt;height&lt;/span&gt; * &lt;span class="hljs-number"&gt;0.3&lt;/span&gt;
                    )

                Text(&lt;span class="hljs-string"&gt;"Width: \(Int(geometry.size.width))"&lt;/span&gt;)
                Text(&lt;span class="hljs-string"&gt;"Height: \(Int(geometry.size.height))"&lt;/span&gt;)
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Caution:&lt;/strong&gt; &lt;code&gt;GeometryReader&lt;/code&gt; expands to fill available space. Use it only when you truly need size information — prefer &lt;code&gt;frame()&lt;/code&gt;, &lt;code&gt;overlay()&lt;/code&gt;, and &lt;code&gt;background()&lt;/code&gt; for most layout tasks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id="19-combine-swiftui"&gt;19. Combine &amp;amp; SwiftUI&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How does SwiftUI integrate with the Combine framework?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;       Combine + &lt;span class="hljs-keyword"&gt;SwiftUI &lt;/span&gt;Integration

  &lt;span class="hljs-meta"&gt;Data&lt;/span&gt; Source ──► Publisher ──► &lt;span class="hljs-keyword"&gt;Subscriber &lt;/span&gt;──► View Update
   (Network,         (Just,        (sink,       (&lt;span class="hljs-keyword"&gt;body
&lt;/span&gt;    Timer,           Future,      assign,       re-renders)
    User input)      PassthroughSubject)  onReceive)
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; Combine
&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; SwiftUI

&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;SearchViewModel&lt;/span&gt;: &lt;span class="hljs-title"&gt;ObservableObject&lt;/span&gt; &lt;/span&gt;{
    @&lt;span class="hljs-type"&gt;Published&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; query = &lt;span class="hljs-string"&gt;""&lt;/span&gt;
    @&lt;span class="hljs-type"&gt;Published&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; results: [&lt;span class="hljs-type"&gt;String&lt;/span&gt;] = []

    &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; cancellables = &lt;span class="hljs-type"&gt;Set&lt;/span&gt;&amp;lt;&lt;span class="hljs-type"&gt;AnyCancellable&lt;/span&gt;&amp;gt;()

    &lt;span class="hljs-keyword"&gt;init&lt;/span&gt;() {
        &lt;span class="hljs-comment"&gt;// Debounce search input — wait 300ms after last keystroke&lt;/span&gt;
        $query
            .debounce(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: .milliseconds(&lt;span class="hljs-number"&gt;300&lt;/span&gt;), scheduler: &lt;span class="hljs-type"&gt;DispatchQueue&lt;/span&gt;.main)
            .removeDuplicates()
            .sink { [&lt;span class="hljs-keyword"&gt;weak&lt;/span&gt; &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;] text &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
                &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;?.performSearch(query: text)
            }
            .store(&lt;span class="hljs-keyword"&gt;in&lt;/span&gt;: &amp;amp;cancellables)
    }

    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;performSearch&lt;/span&gt;&lt;span class="hljs-params"&gt;(query: String)&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-comment"&gt;// Simulate async search&lt;/span&gt;
        results = query.isEmpty ? [] : [&lt;span class="hljs-string"&gt;"Result for '&lt;span class="hljs-subst"&gt;\(query)&lt;/span&gt;'"&lt;/span&gt;]
    }
}

&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;SearchView&lt;/span&gt;: &lt;span class="hljs-title"&gt;View&lt;/span&gt; &lt;/span&gt;{
    @&lt;span class="hljs-type"&gt;StateObject&lt;/span&gt; &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; viewModel = &lt;span class="hljs-type"&gt;SearchViewModel&lt;/span&gt;()

    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; body: some &lt;span class="hljs-type"&gt;View&lt;/span&gt; {
        &lt;span class="hljs-type"&gt;VStack&lt;/span&gt; {
            &lt;span class="hljs-type"&gt;TextField&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Search..."&lt;/span&gt;, text: $viewModel.query)
                .textFieldStyle(.roundedBorder)
                .padding()

            &lt;span class="hljs-type"&gt;List&lt;/span&gt;(viewModel.results, id: \.&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;) { result &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
                &lt;span class="hljs-type"&gt;Text&lt;/span&gt;(result)
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="20-uikit-swiftui-interoperability"&gt;20. UIKit ↔ SwiftUI Interoperability&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How do you use UIKit components in SwiftUI and vice versa?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;     SwiftUI  ←──────────────────────► &lt;span class="hljs-built_in"&gt;UIKit&lt;/span&gt;

     &lt;span class="hljs-built_in"&gt;UIViewRepresentable&lt;/span&gt;                &lt;span class="hljs-built_in"&gt;UIHostingController&lt;/span&gt;
     ┌──────────────────────┐           ┌───────────────────────┐
     │ Wraps a &lt;span class="hljs-built_in"&gt;UIKit&lt;/span&gt; view   │           │ Wraps a SwiftUI view  │
     │ &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; use &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; SwiftUI   │           │ &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; use &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; &lt;span class="hljs-built_in"&gt;UIKit&lt;/span&gt;      │
     │                      │           │                       │
     │ makeUIView()         │           │ let vc =              │
     │ updateUIView()       │           │   &lt;span class="hljs-built_in"&gt;UIHostingController&lt;/span&gt; │
     │ Coordinator (delegate│           │   (rootView: MyView())│
     │  pattern)            │           └───────────────────────┘
     └──────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// UIKit → SwiftUI: Wrap UIKit view with UIViewRepresentable&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;UIKitMapView&lt;/span&gt;: &lt;span class="hljs-title"&gt;UIViewRepresentable&lt;/span&gt; &lt;/span&gt;{
    @&lt;span class="hljs-type"&gt;Binding&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; region: &lt;span class="hljs-type"&gt;MKCoordinateRegion&lt;/span&gt;

    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;makeUIView&lt;/span&gt;&lt;span class="hljs-params"&gt;(context: Context)&lt;/span&gt;&lt;/span&gt; -&amp;gt; &lt;span class="hljs-type"&gt;MKMapView&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; mapView = &lt;span class="hljs-type"&gt;MKMapView&lt;/span&gt;()
        mapView.delegate = context.coordinator
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; mapView
    }

    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;updateUIView&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; mapView: MKMapView, context: Context)&lt;/span&gt;&lt;/span&gt; {
        mapView.setRegion(region, animated: &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)
    }

    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;makeCoordinator&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; -&amp;gt; &lt;span class="hljs-type"&gt;Coordinator&lt;/span&gt; {
        &lt;span class="hljs-type"&gt;Coordinator&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;)
    }

    &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;Coordinator&lt;/span&gt;: &lt;span class="hljs-title"&gt;NSObject&lt;/span&gt;, &lt;span class="hljs-title"&gt;MKMapViewDelegate&lt;/span&gt; &lt;/span&gt;{
        &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; parent: &lt;span class="hljs-type"&gt;UIKitMapView&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;init&lt;/span&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; parent: &lt;span class="hljs-type"&gt;UIKitMapView&lt;/span&gt;) { &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.parent = parent }
    }
}

&lt;span class="hljs-comment"&gt;// SwiftUI → UIKit: Wrap SwiftUI view with UIHostingController&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;MyViewController&lt;/span&gt;: &lt;span class="hljs-title"&gt;UIViewController&lt;/span&gt; &lt;/span&gt;{
    &lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;viewDidLoad&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;super&lt;/span&gt;.viewDidLoad()
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; swiftUIView = &lt;span class="hljs-type"&gt;MySwiftUIView&lt;/span&gt;()
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; hostingController = &lt;span class="hljs-type"&gt;UIHostingController&lt;/span&gt;(rootView: swiftUIView)
        addChild(hostingController)
        view.addSubview(hostingController.view)
        hostingController.didMove(toParent: &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="21-async-await-in-swiftui"&gt;21. Async/Await in SwiftUI&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How do you use async/await for data fetching in SwiftUI?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// ViewModel with async data loading&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;ArticleViewModel&lt;/span&gt;: &lt;span class="hljs-title"&gt;ObservableObject&lt;/span&gt; {
    @Published &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; articles: [Article] = []
    @Published &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; isLoading = &lt;span class="hljs-literal"&gt;false&lt;/span&gt;
    @Published &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; errorMessage: String?

    &lt;span class="hljs-function"&gt;func &lt;span class="hljs-title"&gt;loadArticles&lt;/span&gt;(&lt;span class="hljs-params"&gt;&lt;/span&gt;) &lt;span class="hljs-keyword"&gt;async&lt;/span&gt; &lt;/span&gt;{
        isLoading = &lt;span class="hljs-literal"&gt;true&lt;/span&gt;
        defer { isLoading = &lt;span class="hljs-literal"&gt;false&lt;/span&gt; }

        &lt;span class="hljs-keyword"&gt;do&lt;/span&gt; {
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; url = URL(&lt;span class="hljs-keyword"&gt;string&lt;/span&gt;: &lt;span class="hljs-string"&gt;"https://api.example.com/articles"&lt;/span&gt;)!
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; (data, _) = &lt;span class="hljs-keyword"&gt;try&lt;/span&gt; &lt;span class="hljs-keyword"&gt;await&lt;/span&gt; URLSession.shared.data(&lt;span class="hljs-keyword"&gt;from&lt;/span&gt;: url)
            articles = &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;try&lt;/span&gt; &lt;span class="hljs-title"&gt;JSONDecoder&lt;/span&gt;(&lt;span class="hljs-params"&gt;&lt;/span&gt;).&lt;span class="hljs-title"&gt;decode&lt;/span&gt;(&lt;span class="hljs-params"&gt;[Article].self, &lt;span class="hljs-keyword"&gt;from&lt;/span&gt;: data&lt;/span&gt;)
        } &lt;span class="hljs-keyword"&gt;catch&lt;/span&gt; &lt;/span&gt;{
            errorMessage = error.localizedDescription
        }
    }
}

&lt;span class="hljs-comment"&gt;// View using .task modifier (preferred over .onAppear for async)&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; ArticleListView: View {
    @StateObject &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; viewModel = ArticleViewModel()

    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; body: some View {
        Group {
            &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; viewModel.isLoading {
                ProgressView(&lt;span class="hljs-string"&gt;"Loading..."&lt;/span&gt;)
            } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; error = viewModel.errorMessage {
                Text(&lt;span class="hljs-string"&gt;"Error: \(error)"&lt;/span&gt;).foregroundColor(.red)
            } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
                List(viewModel.articles) { &lt;span class="hljs-function"&gt;article &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
                    &lt;span class="hljs-title"&gt;Text&lt;/span&gt;(&lt;span class="hljs-params"&gt;article.title&lt;/span&gt;)
                }
            }
        }
        .task &lt;/span&gt;{
            &lt;span class="hljs-comment"&gt;// .task is auto-cancelled when view disappears ✅&lt;/span&gt;
            &lt;span class="hljs-keyword"&gt;await&lt;/span&gt; viewModel.loadArticles()
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="-task-vs-onappear"&gt;.task vs .onAppear&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────────────────────┐
│            &lt;span class="hljs-selector-class"&gt;.task&lt;/span&gt;  vs  &lt;span class="hljs-selector-class"&gt;.onAppear&lt;/span&gt;                      │
├─────────────────────────┬────────────────────────────┤
│         &lt;span class="hljs-selector-class"&gt;.task&lt;/span&gt;           │       &lt;span class="hljs-selector-class"&gt;.onAppear&lt;/span&gt;            │
├─────────────────────────┼────────────────────────────┤
│ Native async support    │ Synchronous by default     │
│ Auto-cancels on disappear│ Runs every appearance     │
│ Preferred &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; async ops │ Good &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; simple triggers   │
│ iOS &lt;span class="hljs-number"&gt;15&lt;/span&gt;+                 │ All iOS versions           │
└─────────────────────────┴────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;h2 id="22-mvvm-architecture"&gt;22. MVVM Architecture&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How do you implement MVVM pattern in SwiftUI?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;           MVVM in &lt;span class="hljs-keyword"&gt;SwiftUI
&lt;/span&gt;
  ┌─────────────────────────────────────────────────────┐
  │                                                     │
  │   MODEL              VIEW MODEL           VIEW      │
  │ ┌─────────┐        ┌──────────────┐    ┌────────┐  │
  │ │  &lt;span class="hljs-meta"&gt;Data&lt;/span&gt;   │◄──────►│&lt;span class="hljs-comment"&gt;@Published    │◄──►│SwiftUI │  │&lt;/span&gt;
  │ │ &lt;span class="hljs-keyword"&gt;Struct &lt;/span&gt; │        │ properties   │    │ View   │  │
  │ │  or     │        │              │    │        │  │
  │ │ Entity  │        │ &lt;span class="hljs-keyword"&gt;Business &lt;/span&gt;    │    │&lt;span class="hljs-comment"&gt;@State  │  │&lt;/span&gt;
  │ └─────────┘        │  Logic       │    │&lt;span class="hljs-comment"&gt;@StateObj│ │&lt;/span&gt;
  │                    │              │    │        │  │
  │                    │ ObservableObj│    │        │  │
  │                    └──────────────┘    └────────┘  │
  │                                                     │
  │  &lt;span class="hljs-meta"&gt;Data&lt;/span&gt; / Persistence    Logic Layer     UI Layer     │
  └─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// MODEL&lt;/span&gt;
struct User: Codable, Identifiable {
    let id: UUID
    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; name: String
    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; email: String
}

&lt;span class="hljs-comment"&gt;// VIEW MODEL&lt;/span&gt;
class UserListViewModel: ObservableObject {
    @Published &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; users: [User] = []
    @Published &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; isLoading = false

    private let service: UserService

    init(service: UserService = UserService()) {
        self&lt;span class="hljs-selector-class"&gt;.service&lt;/span&gt; = service
    }

    func fetchUsers() async {
        await MainActor&lt;span class="hljs-selector-class"&gt;.run&lt;/span&gt; { isLoading = true }
        users = await service.getUsers()
        await MainActor&lt;span class="hljs-selector-class"&gt;.run&lt;/span&gt; { isLoading = false }
    }
}

&lt;span class="hljs-comment"&gt;// VIEW&lt;/span&gt;
struct UserListView: View {
    @StateObject private &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; viewModel = UserListViewModel()

    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: some View {
        NavigationStack {
            List(viewModel.users) { user &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
                Text(user.name)
            }
            .navigationTitle(&lt;span class="hljs-string"&gt;"Users"&lt;/span&gt;)
            &lt;span class="hljs-selector-class"&gt;.overlay&lt;/span&gt; { &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; viewModel&lt;span class="hljs-selector-class"&gt;.isLoading&lt;/span&gt; { ProgressView() } }
            &lt;span class="hljs-selector-class"&gt;.task&lt;/span&gt; { await viewModel.fetchUsers() }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="23-performance-optimization"&gt;23. Performance Optimization&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How do you optimize SwiftUI view performance?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;    Performance Optimization Techniques

    &lt;span class="hljs-number"&gt;1.&lt;/span&gt; EQUATABLE VIEWS
    ┌─────────────────────────────────────────┐
    │ struct MyView: View, Equatable { ... }  │
    │ .equatable()  ← skip re-render &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;equal&lt;/span&gt; │
    └─────────────────────────────────────────┘

    &lt;span class="hljs-number"&gt;2.&lt;/span&gt; LAZY CONTAINERS (&lt;span class="hljs-keyword"&gt;for&lt;/span&gt; large lists)
    ┌─────────────────────────────────────────┐
    │ LazyVStack, LazyHStack, LazyVGrid       │
    │ Only renders visible views              │
    └─────────────────────────────────────────┘

    &lt;span class="hljs-number"&gt;3.&lt;/span&gt; PROPER IDENTIFIERS
    ┌─────────────────────────────────────────┐
    │ Use stable IDs &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; ForEach              │
    │ Avoid &lt;span class="hljs-built_in"&gt;id&lt;/span&gt;: \.self &lt;span class="hljs-keyword"&gt;on&lt;/span&gt; mutable objects     │
    └─────────────────────────────────────────┘

    &lt;span class="hljs-number"&gt;4.&lt;/span&gt; @MainActor &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; UI updates
    ┌─────────────────────────────────────────┐
    │ Ensure UI updates happen &lt;span class="hljs-keyword"&gt;on&lt;/span&gt; main thread  │
    └─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-swift"&gt;// ✅ Prefer let over @State when data doesn't &lt;span class="hljs-keyword"&gt;change&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; StaticRow: &lt;span class="hljs-keyword"&gt;View&lt;/span&gt; {
    let title: &lt;span class="hljs-keyword"&gt;String&lt;/span&gt;   // &lt;span class="hljs-keyword"&gt;not&lt;/span&gt; @State — &lt;span class="hljs-keyword"&gt;no&lt;/span&gt; re-render overhead
    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; &lt;span class="hljs-keyword"&gt;body&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;some&lt;/span&gt; &lt;span class="hljs-keyword"&gt;View&lt;/span&gt; { &lt;span class="hljs-built_in"&gt;Text&lt;/span&gt;(title) }
}

// ✅ &lt;span class="hljs-keyword"&gt;Use&lt;/span&gt; .id() &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; &lt;span class="hljs-keyword"&gt;force&lt;/span&gt; &lt;span class="hljs-keyword"&gt;complete&lt;/span&gt; re-&lt;span class="hljs-keyword"&gt;creation&lt;/span&gt; &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; needed
ScrollView {
    LazyVStack {
        ForEach(items) { item &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
            ItemView(item: item)
        }
    }
}

// ✅ &lt;span class="hljs-keyword"&gt;Split&lt;/span&gt; &lt;span class="hljs-keyword"&gt;large&lt;/span&gt; views &lt;span class="hljs-keyword"&gt;into&lt;/span&gt; smaller components
// — SwiftUI &lt;span class="hljs-keyword"&gt;only&lt;/span&gt; re-renders the affected subtree
&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; OptimizedList: &lt;span class="hljs-keyword"&gt;View&lt;/span&gt; {
    @StateObject &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; vm = ListViewModel()

    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; &lt;span class="hljs-keyword"&gt;body&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;some&lt;/span&gt; &lt;span class="hljs-keyword"&gt;View&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;List&lt;/span&gt;(vm.items) { item &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
            ItemRow(item: item)     // separated component
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="24-accessibility-in-swiftui"&gt;24. Accessibility in SwiftUI&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: How does SwiftUI support accessibility?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SwiftUI provides &lt;strong&gt;built-in accessibility support&lt;/strong&gt; that automatically maps standard views to accessibility traits. You can also customize it with dedicated modifiers.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;struct&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;AccessibleView&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;View&lt;/span&gt; {
    &lt;span class="hljs-variable"&gt;@State&lt;/span&gt; private var isFavorite = false

    var &lt;span class="hljs-attribute"&gt;body&lt;/span&gt;: some View {
        &lt;span class="hljs-selector-tag"&gt;VStack&lt;/span&gt; {
            &lt;span class="hljs-comment"&gt;// Image with meaningful accessibility label&lt;/span&gt;
            &lt;span class="hljs-selector-tag"&gt;Image&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;systemName&lt;/span&gt;: isFavorite ? &lt;span class="hljs-string"&gt;"heart.fill"&lt;/span&gt; : &lt;span class="hljs-string"&gt;"heart"&lt;/span&gt;)
                &lt;span class="hljs-selector-class"&gt;.accessibilityLabel&lt;/span&gt;(isFavorite ? &lt;span class="hljs-string"&gt;"Remove from favorites"&lt;/span&gt; : &lt;span class="hljs-string"&gt;"Add to favorites"&lt;/span&gt;)

            &lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;action&lt;/span&gt;: { &lt;span class="hljs-selector-tag"&gt;isFavorite&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.toggle&lt;/span&gt;() }) {
                &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Toggle Favorite"&lt;/span&gt;)
            }
            &lt;span class="hljs-comment"&gt;// Group elements as single accessible unit&lt;/span&gt;
            &lt;span class="hljs-selector-class"&gt;.accessibilityElement&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;children&lt;/span&gt;: .combine)
            &lt;span class="hljs-selector-class"&gt;.accessibilityHint&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Double tap to toggle the favorite state"&lt;/span&gt;)
            &lt;span class="hljs-selector-class"&gt;.accessibilityAddTraits&lt;/span&gt;(.isButton)

            &lt;span class="hljs-comment"&gt;// Custom accessibility value&lt;/span&gt;
            &lt;span class="hljs-selector-tag"&gt;ProgressView&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;value&lt;/span&gt;: &lt;span class="hljs-number"&gt;0.7&lt;/span&gt;)
                &lt;span class="hljs-selector-class"&gt;.accessibilityValue&lt;/span&gt;(&lt;span class="hljs-string"&gt;"70 percent complete"&lt;/span&gt;)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="25-common-interview-traps-tips"&gt;25. Common Interview Traps &amp;amp; Tips&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q: What are some common SwiftUI gotchas interviewers test?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="-common-traps"&gt;⚠️ Common Traps&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                    &lt;span class="hljs-selector-tag"&gt;Interview&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Gotchas&lt;/span&gt;                             │
├─────────────────────┬───────────────────────────────────────────┤
│  &lt;span class="hljs-selector-tag"&gt;Topic&lt;/span&gt;              │   &lt;span class="hljs-selector-tag"&gt;Common&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Mistake&lt;/span&gt;                          │
├─────────────────────┼───────────────────────────────────────────┤
│ @&lt;span class="hljs-selector-tag"&gt;State&lt;/span&gt;              │ &lt;span class="hljs-selector-tag"&gt;Using&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;it&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;in&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;a&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;ViewModel&lt;/span&gt; (should be in     │
│                     │ the View only, not ObservableObject)      │
├─────────────────────┼───────────────────────────────────────────┤
│ @&lt;span class="hljs-selector-tag"&gt;StateObject&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;vs&lt;/span&gt;     │ &lt;span class="hljs-selector-tag"&gt;Using&lt;/span&gt; @&lt;span class="hljs-selector-tag"&gt;ObservedObject&lt;/span&gt; &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; the View       │
│ &lt;span class="hljs-variable"&gt;@ObservedObject&lt;/span&gt;     │ creates the object (causes data loss      │
│                     │ on re-render)                             │
├─────────────────────┼───────────────────────────────────────────┤
│ Modifier Order      │ Forgetting that .padding() before         │
│                     │ .background() behaves differently         │
├─────────────────────┼───────────────────────────────────────────┤
│ GeometryReader      │ Overusing it — causes unexpected          │
│                     │ layout behavior; prefer other tools       │
├─────────────────────┼───────────────────────────────────────────┤
│ List identity       │ Using &lt;span class="hljs-attribute"&gt;id&lt;/span&gt;: \.self on mutable objects       │
│                     │ causes incorrect diff updates             │
├─────────────────────┼───────────────────────────────────────────┤
│ &lt;span class="hljs-variable"&gt;@EnvironmentObject&lt;/span&gt;  │ Forgetting to inject it at the root       │
│                     │ causes a crash at runtime                 │
├─────────────────────┼───────────────────────────────────────────┤
│ .task vs .onAppear  │ Using .onAppear with async code instead   │
│                     │ of .task (task auto-cancels properly)     │
└─────────────────────┴───────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="-top-tips-for-swiftui-interviews"&gt;&#127919; Top Tips for SwiftUI Interviews&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Always explain WHY, not just WHAT&lt;/strong&gt; — interviewers want reasoning behind choices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Know the property wrapper lifecycle&lt;/strong&gt; deeply (&lt;code&gt;@StateObject&lt;/code&gt; vs &lt;code&gt;@ObservedObject&lt;/code&gt; is a very common question)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Be able to draw the data flow&lt;/strong&gt; — one-directional, reactive, state → UI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mention backward compatibility&lt;/strong&gt; — SwiftUI features have different iOS version requirements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Talk about MVVM naturally&lt;/strong&gt; — it's the de-facto pattern for SwiftUI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mention &lt;code&gt;.task&lt;/code&gt; for async&lt;/strong&gt; — shows you know modern concurrency integration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discuss testing&lt;/strong&gt; — ViewInspector, Preview-driven development, ViewModel unit tests&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id="-quick-revision-summary"&gt;&#128218; Quick Revision Summary&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────┐
│                  &lt;span class="hljs-keyword"&gt;SwiftUI &lt;/span&gt;Mental Model                         │
│                                                               │
│  UI = f(State)                                                │
│                                                               │
│  ┌──────────┐    changes    ┌──────────┐    renders          │
│  │  State   │ ────────────► │ &lt;span class="hljs-keyword"&gt;SwiftUI &lt;/span&gt; │ ────────────► UI    │
│  │ &lt;span class="hljs-comment"&gt;@State   │               │ Engine   │                     │&lt;/span&gt;
│  │ &lt;span class="hljs-comment"&gt;@Published│              │ (diffing)│                     │&lt;/span&gt;
│  │ &lt;span class="hljs-comment"&gt;@Binding │               └──────────┘                     │&lt;/span&gt;
│  └──────────┘                                                 │
│                                                               │
│  Views are value types (&lt;span class="hljs-keyword"&gt;structs) &lt;/span&gt;— cheap to re-create        │
│  State lives outside the view — owned &lt;span class="hljs-keyword"&gt;by &lt;/span&gt;&lt;span class="hljs-keyword"&gt;SwiftUI &lt;/span&gt;            │
│  &lt;span class="hljs-meta"&gt;Data&lt;/span&gt; flows down (one-way), events flow up (actions)         │
└──────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;h2 id="-tags"&gt;&#127991;️ Tags&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;SwiftUI&lt;/code&gt; &lt;code&gt;iOS&lt;/code&gt; &lt;code&gt;Swift&lt;/code&gt; &lt;code&gt;Apple&lt;/code&gt; &lt;code&gt;Mobile Development&lt;/code&gt; &lt;code&gt;Interview Prep&lt;/code&gt; &lt;code&gt;UIKit&lt;/code&gt; &lt;code&gt;Xcode&lt;/code&gt; &lt;code&gt;MVVM&lt;/code&gt; &lt;code&gt;Combine&lt;/code&gt; &lt;code&gt;Async/Await&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;&#128221; Last updated: 2025 | Covers iOS 13 → iOS 17+ SwiftUI features&lt;/em&gt;&lt;/p&gt;
</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>&#128241; UIKit iOS Development from First Principles — A SecureRoom Deep Dive</title><link>https://flutdev.blogspot.com/2026/02/uikit-ios-development-from-first.html</link><category>IOS</category><category>Swift</category><category>UIKit</category><author>noreply@blogger.com (Lokesh Jangid)</author><pubDate>Mon, 23 Feb 2026 21:03:00 -0800</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7439341812408440578.post-8450612264876399958</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A complete breakdown of every layer of a real-world UIKit app.&lt;/strong&gt;
Based on the open-source &lt;a href="https://github.com/lkrjangid1/SecureRoom"&gt;SecureRoom&lt;/a&gt; project — a passcode-protected secure vault app built with &lt;strong&gt;UIKit&lt;/strong&gt;, &lt;strong&gt;Storyboards&lt;/strong&gt;, &lt;strong&gt;Core Data&lt;/strong&gt;, and the &lt;strong&gt;iOS Keychain&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;⚠️ This guide deliberately contrasts UIKit&amp;#39;s imperative style against SwiftUI&amp;#39;s declarative approach wherever relevant, so you understand &lt;em&gt;why&lt;/em&gt; things are done the way they are.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="what-is-secureroom-"&gt;What is SecureRoom?&lt;/h2&gt;
&lt;p&gt;SecureRoom is a &lt;strong&gt;passcode-protected vault app&lt;/strong&gt;. On launch it shows a 4-digit PIN entry screen. The user sets a passcode on first run (saved to the iOS Keychain), and must enter it every time the app is opened or brought back from the background. Passing the PIN reveals a &lt;code&gt;UITabBarController&lt;/code&gt;-based home screen with three tabs (Home, Add, Settings).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tech stack:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Language:&lt;/strong&gt; Swift 5.9&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UI Framework:&lt;/strong&gt; UIKit&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UI Design:&lt;/strong&gt; Storyboards + Auto Layout&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture:&lt;/strong&gt; MVC (Model-View-Controller)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secure Storage:&lt;/strong&gt; iOS Keychain (&lt;code&gt;Security&lt;/code&gt; framework)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local Persistence:&lt;/strong&gt; Core Data (&lt;code&gt;NSPersistentContainer&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigation:&lt;/strong&gt; &lt;code&gt;UIWindow.rootViewController&lt;/code&gt; swaps + &lt;code&gt;UITabBarController&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="uikit-vs-swiftui-the-core-difference"&gt;UIKit vs SwiftUI — The Core Difference&lt;/h2&gt;
&lt;p&gt;Before diving into code, understand the fundamental philosophy difference:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;UIKit&lt;/th&gt;
&lt;th&gt;SwiftUI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Paradigm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Imperative&lt;/strong&gt; — you tell the system &lt;em&gt;how&lt;/em&gt; to update step by step&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Declarative&lt;/strong&gt; — you describe &lt;em&gt;what&lt;/em&gt; the UI should look like for a given state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UI Design&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Storyboards (visual XML) or code with &lt;code&gt;addSubview&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pure Swift code in &lt;code&gt;body&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Controllers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIViewController&lt;/code&gt; classes manage views&lt;/td&gt;
&lt;td&gt;&lt;code&gt;View&lt;/code&gt; structs own their state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@IBOutlet&lt;/code&gt; properties + manual &lt;code&gt;label.text = &amp;quot;...&amp;quot;&lt;/code&gt; updates&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@State&lt;/code&gt;, &lt;code&gt;@Published&lt;/code&gt; — UI auto-updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Introduced&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;iOS 2 (2008)&lt;/td&gt;
&lt;td&gt;iOS 13 (2019)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Current use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vast majority of production apps, all legacy codebases&lt;/td&gt;
&lt;td&gt;Greenfield apps, Apple&amp;#39;s future&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In UIKit, when data changes, &lt;strong&gt;you write the code that updates the UI&lt;/strong&gt;. In SwiftUI, you change state and the framework re-renders. This is the fundamental difference.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// UIKit — imperative: you manually update the label&lt;/span&gt;
messageLabel&lt;span class="hljs-selector-class"&gt;.text&lt;/span&gt; = &lt;span class="hljs-string"&gt;"Welcome, create a passcode"&lt;/span&gt;

&lt;span class="hljs-comment"&gt;// SwiftUI — declarative: the UI is always derived from state&lt;/span&gt;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-title"&gt;Text&lt;/span&gt;&lt;span class="hljs-params"&gt;(viewModel.message)&lt;/span&gt;&lt;/span&gt;   &lt;span class="hljs-comment"&gt;// auto-updates when viewModel.message changes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="project-architecture-mvc"&gt;Project Architecture — MVC&lt;/h2&gt;
&lt;p&gt;UIKit was built around &lt;strong&gt;MVC (Model-View-Controller)&lt;/strong&gt;, Apple&amp;#39;s original iOS design pattern.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                         USER ACTION                          │
│                    (taps Submit button)                      │
└──────────────────────────┬──────────────────────────────────┘
                           │ IBAction
                           ▼
┌─────────────────────────────────────────────────────────────┐
│              CONTROLLER (UIViewController)                   │
│   LockScreenViewController — receives events, reads IBOutlets│
│   → calls KeychainManager (Helper/Service)                  │
│   → decides what to &lt;span class="hljs-keyword"&gt;do&lt;/span&gt; &lt;span class="hljs-keyword"&gt;next&lt;/span&gt; (&lt;span class="hljs-keyword"&gt;show&lt;/span&gt; alert / navigate)         │
│   → directly updates &lt;span class="hljs-keyword"&gt;View&lt;/span&gt; properties (label.text = ...)     │
└──────────┬──────────────────────────────────────────────────┘
           │                    │
           ▼                    ▼
┌──────────────────┐   ┌───────────────────────────────────┐
│   &lt;span class="hljs-keyword"&gt;MODEL&lt;/span&gt;          │   │   &lt;span class="hljs-keyword"&gt;VIEW&lt;/span&gt; (Storyboard + UIKit)        │
│   Secret.swift   │   │   UILabel, UITextField, UIButton   │
│   (&lt;span class="hljs-keyword"&gt;data&lt;/span&gt; &lt;span class="hljs-keyword"&gt;struct&lt;/span&gt;)  │   │   &lt;span class="hljs-keyword"&gt;Auto&lt;/span&gt; Layout &lt;span class="hljs-keyword"&gt;constraints&lt;/span&gt;          │
└──────────────────┘   └───────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In MVC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model&lt;/strong&gt; holds data — plain structs/classes, no UIKit imports&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View&lt;/strong&gt; is the visual layer — in UIKit this is managed mostly by Storyboard XML&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controller&lt;/strong&gt; is the bridge — it reads user input from the View, manipulates the Model, and updates the View manually&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The main criticism of MVC in iOS is that ViewControllers tend to grow very large (&amp;quot;Massive View Controller&amp;quot;) because they own both the business logic and the view manipulation code.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="folder-structure"&gt;Folder Structure&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;SecureRoom/
└── SecureRoom/                           ← Xcode project root
    ├── AppDelegate&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;                 ← App lifecycle + Core Data stack
    ├── SceneDelegate&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;               ← Window/scene management + lock-on-&lt;span class="hljs-attribute"&gt;background&lt;/span&gt;
    ├── ViewController&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;              ← Unused base VC (Xcode default)
    ├── Controllers/
    │   ├── LockScreenViewController&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt; ← &lt;span class="hljs-number"&gt;4&lt;/span&gt;-digit PIN screen (full logic)
    │   └── HomeViewController&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;       ← Home screen (scaffold)
    ├── Helpers/
    │   ├── Constants&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;               ← Global constants (passcodeKey)
    │   └── KeychainManager&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;         ← iOS Keychain save/read/delete
    ├── Models/
    │   └── Secret&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;                  ← SecretModel data struct
    ├── Storyboards/
    │   ├── LockScreen&lt;span class="hljs-selector-class"&gt;.storyboard&lt;/span&gt;         ← Lock screen UI (&lt;span class="hljs-number"&gt;4&lt;/span&gt; textfields, &lt;span class="hljs-selector-tag"&gt;button&lt;/span&gt;, label)
    │   └── HomeScreen&lt;span class="hljs-selector-class"&gt;.storyboard&lt;/span&gt;         ← Tab bar controller with &lt;span class="hljs-number"&gt;3&lt;/span&gt; tabs
    └── Assets&lt;span class="hljs-selector-class"&gt;.xcassets&lt;/span&gt;                   ← App &lt;span class="hljs-attribute"&gt;icon&lt;/span&gt;, Logo image, colors
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="app-lifecycle-appdelegate-scenedelegate"&gt;App Lifecycle — AppDelegate &amp;amp; SceneDelegate&lt;/h2&gt;
&lt;p&gt;UIKit apps have &lt;strong&gt;two lifecycle entry points&lt;/strong&gt;: &lt;code&gt;AppDelegate&lt;/code&gt; (app-wide) and &lt;code&gt;SceneDelegate&lt;/code&gt; (per-window). This two-delegate system was introduced in iOS 13 to support multi-window on iPad.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="appdelegate-swift"&gt;AppDelegate.swift&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;AppDelegate&lt;/code&gt; is the &lt;strong&gt;oldest lifecycle hook&lt;/strong&gt; in iOS. It&amp;#39;s called by the OS for app-wide events that are not tied to any specific window.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; UIKit
&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; CoreData

@main   &lt;span class="hljs-comment"&gt;// marks this class as the entry point (replaces main.swift)&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;AppDelegate&lt;/span&gt;: &lt;span class="hljs-title"&gt;UIResponder&lt;/span&gt;, &lt;span class="hljs-title"&gt;UIApplicationDelegate&lt;/span&gt; &lt;/span&gt;{

    &lt;span class="hljs-comment"&gt;// Called once when the app process launches — before any UI appears&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;application&lt;/span&gt;&lt;span class="hljs-params"&gt;(
        &lt;span class="hljs-number"&gt;_&lt;/span&gt; application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    )&lt;/span&gt;&lt;/span&gt; -&amp;gt; &lt;span class="hljs-type"&gt;Bool&lt;/span&gt; {
        &lt;span class="hljs-comment"&gt;// Ideal place to: configure SDKs, set up analytics, configure appearance&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;  &lt;span class="hljs-comment"&gt;// must return true unless launch should be aborted&lt;/span&gt;
    }

    &lt;span class="hljs-comment"&gt;// Called when a NEW scene (window) is about to be created&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;// Returns a configuration object — "Default Configuration" matches Info.plist&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;application&lt;/span&gt;&lt;span class="hljs-params"&gt;(
        &lt;span class="hljs-number"&gt;_&lt;/span&gt; application: UIApplication,
        configurationForConnecting connectingSceneSession: UISceneSession,
        options: UIScene.ConnectionOptions
    )&lt;/span&gt;&lt;/span&gt; -&amp;gt; &lt;span class="hljs-type"&gt;UISceneConfiguration&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-type"&gt;UISceneConfiguration&lt;/span&gt;(name: &lt;span class="hljs-string"&gt;"Default Configuration"&lt;/span&gt;, sessionRole: connectingSceneSession.role)
    }

    &lt;span class="hljs-comment"&gt;// Called when the user closes a scene (e.g. swipes away in the App Switcher)&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;application&lt;/span&gt;&lt;span class="hljs-params"&gt;(
        &lt;span class="hljs-number"&gt;_&lt;/span&gt; application: UIApplication,
        didDiscardSceneSessions sceneSessions: Set&amp;lt;UISceneSession&amp;gt;
    )&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-comment"&gt;// Release any resources specific to those scenes here&lt;/span&gt;
    }

    &lt;span class="hljs-comment"&gt;// MARK: - Core Data stack&lt;/span&gt;
    &lt;span class="hljs-built_in"&gt;lazy&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; persistentContainer: &lt;span class="hljs-type"&gt;NSPersistentContainer&lt;/span&gt; = {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; container = &lt;span class="hljs-type"&gt;NSPersistentContainer&lt;/span&gt;(name: &lt;span class="hljs-string"&gt;"SecureRoom"&lt;/span&gt;)
        container.loadPersistentStores { storeDescription, error &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
            &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; error = error &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-type"&gt;NSError&lt;/span&gt;? {
                &lt;span class="hljs-built_in"&gt;fatalError&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Unresolved error &lt;span class="hljs-subst"&gt;\(error)&lt;/span&gt;, &lt;span class="hljs-subst"&gt;\(error.userInfo)&lt;/span&gt;"&lt;/span&gt;)
            }
        }
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; container
    }()

    &lt;span class="hljs-comment"&gt;// Called by SceneDelegate.sceneDidEnterBackground to persist Core Data changes&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;saveContext&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; context = persistentContainer.viewContext
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; context.hasChanges {
            &lt;span class="hljs-keyword"&gt;do&lt;/span&gt; {
                &lt;span class="hljs-keyword"&gt;try&lt;/span&gt; context.save()
            } &lt;span class="hljs-keyword"&gt;catch&lt;/span&gt; {
                &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; nserror = error &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-type"&gt;NSError&lt;/span&gt;
                &lt;span class="hljs-built_in"&gt;fatalError&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Unresolved error &lt;span class="hljs-subst"&gt;\(nserror)&lt;/span&gt;, &lt;span class="hljs-subst"&gt;\(nserror.userInfo)&lt;/span&gt;"&lt;/span&gt;)
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="key-appdelegate-concepts"&gt;Key AppDelegate concepts&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIResponder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Base class for objects that can respond to touch events. &lt;code&gt;AppDelegate&lt;/code&gt; and &lt;code&gt;UIViewController&lt;/code&gt; both inherit from it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIApplicationDelegate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Protocol that declares all lifecycle callback methods the OS calls. You only implement the ones you need.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@main&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tells Swift this class is the app&amp;#39;s entry point. Replaces the old &lt;code&gt;main.swift&lt;/code&gt; file. In UIKit apps this is always on &lt;code&gt;AppDelegate&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;didFinishLaunchingWithOptions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called once after the app process starts and the main storyboard loads. Ideal for SDK configuration (Firebase, Crashlytics, etc.).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lazy var&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The property is only computed on first access. &lt;code&gt;persistentContainer&lt;/code&gt; can take time to initialise, so &lt;code&gt;lazy&lt;/code&gt; defers the work until it&amp;#39;s actually needed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NSPersistentContainer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Core Data&amp;#39;s all-in-one setup — manages the persistent store, object model, and managed object context.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="scenedelegate-swift"&gt;SceneDelegate.swift&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;SceneDelegate&lt;/code&gt; manages a &lt;strong&gt;single window&lt;/strong&gt; (scene). Most iPhone apps have exactly one scene. The SceneDelegate handles the lifecycle of that specific window — including when it enters the background (where SecureRoom locks itself).&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; UIKit

&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;SceneDelegate&lt;/span&gt;: &lt;span class="hljs-title"&gt;UIResponder&lt;/span&gt;, &lt;span class="hljs-title"&gt;UIWindowSceneDelegate&lt;/span&gt; &lt;/span&gt;{

    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; window: &lt;span class="hljs-type"&gt;UIWindow&lt;/span&gt;?  &lt;span class="hljs-comment"&gt;// the actual window object that contains all views&lt;/span&gt;

    &lt;span class="hljs-comment"&gt;// Called when the scene is about to connect to the app&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;// This is where you configure the root view controller&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;scene&lt;/span&gt;&lt;span class="hljs-params"&gt;(
        &lt;span class="hljs-number"&gt;_&lt;/span&gt; scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    )&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-comment"&gt;// Cast to UIWindowScene — the concrete type for iOS windows&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; windowScene = (scene &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;? &lt;span class="hljs-type"&gt;UIWindowScene&lt;/span&gt;) &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; }

        &lt;span class="hljs-comment"&gt;// Create the UIWindow manually (overrides storyboard-based window creation)&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; window = &lt;span class="hljs-type"&gt;UIWindow&lt;/span&gt;(windowScene: windowScene)
        &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.window = window

        &lt;span class="hljs-comment"&gt;// Load LockScreen storyboard and set it as the root&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; storyboard = &lt;span class="hljs-type"&gt;UIStoryboard&lt;/span&gt;(name: &lt;span class="hljs-string"&gt;"LockScreen"&lt;/span&gt;, bundle: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;)
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; lockVc = storyboard.instantiateInitialViewController()

        window.rootViewController = lockVc
        window.makeKeyAndVisible()  &lt;span class="hljs-comment"&gt;// makes this window the key window + shows it&lt;/span&gt;
    }

    &lt;span class="hljs-comment"&gt;// Scene lifecycle hooks — called at specific points in the window lifecycle&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;sceneDidDisconnect&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; scene: UIScene)&lt;/span&gt;&lt;/span&gt; { }       &lt;span class="hljs-comment"&gt;// scene removed from memory&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;sceneDidBecomeActive&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; scene: UIScene)&lt;/span&gt;&lt;/span&gt; { }     &lt;span class="hljs-comment"&gt;// scene is now active (in foreground)&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;sceneWillResignActive&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; scene: UIScene)&lt;/span&gt;&lt;/span&gt; { }    &lt;span class="hljs-comment"&gt;// about to become inactive (call, notification)&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;sceneWillEnterForeground&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; scene: UIScene)&lt;/span&gt;&lt;/span&gt; { } &lt;span class="hljs-comment"&gt;// coming back from background&lt;/span&gt;

    &lt;span class="hljs-comment"&gt;// Called when app goes to background — CRITICAL for SecureRoom&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;sceneDidEnterBackground&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; scene: UIScene)&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-comment"&gt;// 1. Save any unsaved Core Data changes&lt;/span&gt;
        (&lt;span class="hljs-type"&gt;UIApplication&lt;/span&gt;.shared.delegate &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;? &lt;span class="hljs-type"&gt;AppDelegate&lt;/span&gt;)?.saveContext()
        &lt;span class="hljs-comment"&gt;// 2. Lock the screen&lt;/span&gt;
        lockScreen()
    }

    &lt;span class="hljs-comment"&gt;// Replaces the window's root VC with the lock screen&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;lockScreen&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; storyboard = &lt;span class="hljs-type"&gt;UIStoryboard&lt;/span&gt;(name: &lt;span class="hljs-string"&gt;"LockScreen"&lt;/span&gt;, bundle: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;)
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; lockVc = storyboard.instantiateInitialViewController()

        &lt;span class="hljs-comment"&gt;// DispatchQueue.main.async ensures UI work runs on the main thread&lt;/span&gt;
        &lt;span class="hljs-type"&gt;DispatchQueue&lt;/span&gt;.main.async {
            &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.window?.rootViewController = lockVc
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="scene-lifecycle-order"&gt;Scene lifecycle order&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;App cold launch:
willConnectTo → sceneDidBecomeActive

&lt;span class="hljs-keyword"&gt;User&lt;/span&gt; &lt;span class="hljs-title"&gt;presses&lt;/span&gt; Home button:
sceneWillResignActive → sceneDidEnterBackground   ← SecureRoom locks here

&lt;span class="hljs-keyword"&gt;User&lt;/span&gt; &lt;span class="hljs-title"&gt;reopens&lt;/span&gt; app from App Switcher:
sceneWillEnterForeground → sceneDidBecomeActive
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="key-scenedelegate-concepts"&gt;Key SceneDelegate concepts&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIWindowSceneDelegate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Protocol for per-window lifecycle callbacks. Introduced iOS 13.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The invisible container that holds all views. Every app needs at least one. Normally created automatically via storyboard, but here created manually for full control.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIWindowScene&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The scene type for iPhone/iPad windows (as opposed to CarPlay or Watch).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;window.rootViewController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The topmost view controller visible on screen. Swapping this is the most direct way to completely change screens in UIKit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;makeKeyAndVisible()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Makes this window the &lt;strong&gt;key window&lt;/strong&gt; (the one that receives keyboard input) and makes it visible. Without this, nothing appears.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIStoryboard(name:bundle:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Loads a storyboard file by name. &lt;code&gt;bundle: nil&lt;/code&gt; means the main app bundle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;instantiateInitialViewController()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates the view controller marked as &amp;quot;Initial View Controller&amp;quot; in the storyboard. Returns &lt;code&gt;UIViewController?&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DispatchQueue.main.async { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Schedules a closure to run on the main thread asynchronously. &lt;strong&gt;All UIKit updates must happen on the main thread.&lt;/strong&gt; Failure to do this causes crashes or visual glitches.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIApplication.shared.delegate as? AppDelegate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gets the global app delegate instance to call &lt;code&gt;saveContext()&lt;/code&gt;. The &lt;code&gt;as?&lt;/code&gt; is a conditional downcast — &lt;code&gt;AppDelegate&lt;/code&gt; is a specific subclass; the delegate property is typed as the generic &lt;code&gt;UIApplicationDelegate&lt;/code&gt; protocol.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="core-data-stack-inside-appdelegate"&gt;Core Data Stack inside AppDelegate&lt;/h3&gt;
&lt;p&gt;Core Data is Apple&amp;#39;s object graph persistence framework — it stores structured data locally on device in a SQLite database (by default).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NSPersistentContainer (&lt;span class="hljs-string"&gt;"SecureRoom"&lt;/span&gt;)
         │
         ├── NSManagedObjectModel      ← defines entities/attributes (&lt;span class="hljs-built_in"&gt;from&lt;/span&gt; .xcdatamodeld &lt;span class="hljs-built_in"&gt;file&lt;/span&gt;)
         ├── NSPersistentStoreCoordinator ← manages &lt;span class="hljs-keyword"&gt;the&lt;/span&gt; actual SQLite &lt;span class="hljs-built_in"&gt;file&lt;/span&gt; &lt;span class="hljs-keyword"&gt;on&lt;/span&gt; &lt;span class="hljs-title"&gt;disk&lt;/span&gt;
         └── NSManagedObjectContext (viewContext) ← &lt;span class="hljs-keyword"&gt;the&lt;/span&gt; &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;-memory scratchpad you work &lt;span class="hljs-keyword"&gt;with&lt;/span&gt;
                    │
                    ├── fetch → &lt;span class="hljs-built_in"&gt;read&lt;/span&gt; objects &lt;span class="hljs-built_in"&gt;from&lt;/span&gt; SQLite
                    ├── insert → &lt;span class="hljs-built_in"&gt;create&lt;/span&gt; &lt;span class="hljs-built_in"&gt;new&lt;/span&gt; objects
                    ├── &lt;span class="hljs-built_in"&gt;delete&lt;/span&gt; → mark objects &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; deletion
                    └── save() → writes all changes &lt;span class="hljs-built_in"&gt;to&lt;/span&gt; SQLite
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;How to use the context in a View Controller:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Get the context from AppDelegate&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; context = (UIApplication.shared.&lt;span class="hljs-keyword"&gt;delegate&lt;/span&gt; &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;! AppDelegate).persistentContainer.viewContext

&lt;span class="hljs-comment"&gt;// Fetch all secrets&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; request: NSFetchRequest&amp;lt;SecretEntity&amp;gt; = SecretEntity.fetchRequest()
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; secrets = &lt;span class="hljs-keyword"&gt;try&lt;/span&gt;? context.fetch(request)

&lt;span class="hljs-comment"&gt;// Insert a new object&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; secret = SecretEntity(context: context)
secret.title = &lt;span class="hljs-string"&gt;"My password"&lt;/span&gt;
secret.&lt;span class="hljs-keyword"&gt;value&lt;/span&gt; = &lt;span class="hljs-string"&gt;"hunter2"&lt;/span&gt;

&lt;span class="hljs-comment"&gt;// Save to disk&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;try&lt;/span&gt;? context.save()
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="storyboards-designing-ui-visually"&gt;Storyboards — Designing UI Visually&lt;/h2&gt;
&lt;h3 id="what-is-a-storyboard-"&gt;What is a Storyboard?&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;Storyboard&lt;/strong&gt; is an XML file (&lt;code&gt;.storyboard&lt;/code&gt;) that describes your UI visually. Xcode renders it as a drag-and-drop canvas. At build time, Xcode compiles the XML into the app bundle, and UIKit reads it at runtime to instantiate views.&lt;/p&gt;
&lt;p&gt;You never hand-edit the XML — Xcode&amp;#39;s Interface Builder does it. But understanding the XML structure helps you debug connection issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storyboard file → XML structure:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;document&lt;/span&gt;&amp;gt;&lt;/span&gt;                          ← the storyboard file
  &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;scenes&lt;/span&gt;&amp;gt;&lt;/span&gt;                          ← array of screens
    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;scene&lt;/span&gt;&amp;gt;&lt;/span&gt;                         ← one screen / view controller
      &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;objects&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;viewController&lt;/span&gt;             ← &lt;span class="hljs-attr"&gt;maps&lt;/span&gt; &lt;span class="hljs-attr"&gt;to&lt;/span&gt; &lt;span class="hljs-attr"&gt;a&lt;/span&gt; &lt;span class="hljs-attr"&gt;UIViewController&lt;/span&gt; &lt;span class="hljs-attr"&gt;subclass&lt;/span&gt;
          &lt;span class="hljs-attr"&gt;customClass&lt;/span&gt;=&lt;span class="hljs-string"&gt;"LockScreenViewController"&lt;/span&gt;
        &amp;gt;&lt;/span&gt;
          &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;view&lt;/span&gt;&amp;gt;&lt;/span&gt;                    ← the root UIView
            &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;subviews&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;label&lt;/span&gt; &lt;span class="hljs-attr"&gt;...&lt;/span&gt;/&amp;gt;&lt;/span&gt;          ← UILabel
              &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;textField&lt;/span&gt; &lt;span class="hljs-attr"&gt;...&lt;/span&gt;/&amp;gt;&lt;/span&gt;      ← UITextField
              &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;button&lt;/span&gt; &lt;span class="hljs-attr"&gt;...&lt;/span&gt;/&amp;gt;&lt;/span&gt;         ← UIButton
              &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;stackView&lt;/span&gt;&amp;gt;&lt;/span&gt;           ← UIStackView
                &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;subviews&lt;/span&gt;&amp;gt;&lt;/span&gt; ... &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;subviews&lt;/span&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;stackView&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;subviews&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;constraints&lt;/span&gt;&amp;gt;&lt;/span&gt; ... &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;constraints&lt;/span&gt;&amp;gt;&lt;/span&gt;   ← Auto Layout rules
          &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;view&lt;/span&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;connections&lt;/span&gt;&amp;gt;&lt;/span&gt;             ← IBOutlet and IBAction connections
            &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;outlet&lt;/span&gt; &lt;span class="hljs-attr"&gt;property&lt;/span&gt;=&lt;span class="hljs-string"&gt;"messageLabel"&lt;/span&gt; &lt;span class="hljs-attr"&gt;destination&lt;/span&gt;=&lt;span class="hljs-string"&gt;"labelID"&lt;/span&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;action&lt;/span&gt; &lt;span class="hljs-attr"&gt;selector&lt;/span&gt;=&lt;span class="hljs-string"&gt;"verify:"&lt;/span&gt; &lt;span class="hljs-attr"&gt;destination&lt;/span&gt;=&lt;span class="hljs-string"&gt;"vcID"&lt;/span&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;connections&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;viewController&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;objects&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;scene&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;scenes&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;document&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h3 id="lockscreen-storyboard-layout-breakdown"&gt;LockScreen.storyboard — Layout Breakdown&lt;/h3&gt;
&lt;p&gt;From the storyboard XML, the LockScreen contains:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-built_in"&gt;UIView&lt;/span&gt; (root)  backgroundColor = systemBackground
│
├── &lt;span class="hljs-built_in"&gt;UIImageView&lt;/span&gt;            — Logo image, centred, width = &lt;span class="hljs-number"&gt;50&lt;/span&gt;% of screen
│
├── &lt;span class="hljs-built_in"&gt;UILabel&lt;/span&gt;                — &lt;span class="hljs-string"&gt;"SecureRoom"&lt;/span&gt; title
│                            font: Copperplate-Bold, size &lt;span class="hljs-number"&gt;32&lt;/span&gt;
│
├── &lt;span class="hljs-built_in"&gt;UIStackView&lt;/span&gt;            — horizontal, distribution: fillEqually, spacing: &lt;span class="hljs-number"&gt;20&lt;/span&gt;
│   ├── &lt;span class="hljs-built_in"&gt;UITextField&lt;/span&gt; [&lt;span class="hljs-number"&gt;1&lt;/span&gt;]    — one digit, borderStyle: roundedRect, centred
│   ├── &lt;span class="hljs-built_in"&gt;UITextField&lt;/span&gt; [&lt;span class="hljs-number"&gt;2&lt;/span&gt;]    — one digit
│   ├── &lt;span class="hljs-built_in"&gt;UITextField&lt;/span&gt; [&lt;span class="hljs-number"&gt;3&lt;/span&gt;]    — one digit
│   └── &lt;span class="hljs-built_in"&gt;UITextField&lt;/span&gt; [&lt;span class="hljs-number"&gt;4&lt;/span&gt;]    — one digit, textContentType: one-time-code
│
├── &lt;span class="hljs-built_in"&gt;UIButton&lt;/span&gt;               — &lt;span class="hljs-string"&gt;"Submit"&lt;/span&gt;, style: filled, cornerStyle: large
│                            SF Symbol: arrowshape.right
│                            action → verifyWithSender:
│
└── &lt;span class="hljs-built_in"&gt;UILabel&lt;/span&gt; (messageLabel) — &lt;span class="hljs-string"&gt;"Welcome create a passcode"&lt;/span&gt; / &lt;span class="hljs-string"&gt;"Enter passcode"&lt;/span&gt;
                             pinned to bottom safe area
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Auto Layout constraint summary&lt;/strong&gt; (from the XML):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Logo: &lt;code&gt;top = safeArea.top&lt;/code&gt;, &lt;code&gt;centerX = view.centerX&lt;/code&gt;, &lt;code&gt;width = view.width * 0.5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Title: &lt;code&gt;top = logo.bottom + 5&lt;/code&gt;, &lt;code&gt;centerX = view.centerX&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;StackView: &lt;code&gt;top = title.bottom + 40&lt;/code&gt;, &lt;code&gt;leading = safeArea.leading + 30&lt;/code&gt;, &lt;code&gt;trailing = safeArea.trailing - 30&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Submit button: &lt;code&gt;top = stackView.bottom + 30&lt;/code&gt;, &lt;code&gt;centerX = view.centerX&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Message label: &lt;code&gt;bottom = safeArea.bottom - 30&lt;/code&gt;, &lt;code&gt;centerX = view.centerX&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="homescreen-storyboard-uitabbarcontroller"&gt;HomeScreen.storyboard — UITabBarController&lt;/h3&gt;
&lt;p&gt;The home screen uses a &lt;code&gt;UITabBarController&lt;/code&gt; as the root, containing three tabs wired to three view controllers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UITabBarController (initialViewController)
│
├── Tab &lt;span class="hljs-number"&gt;1&lt;/span&gt; — &lt;span class="hljs-string"&gt;"Home"&lt;/span&gt;  (house.circle icon)
│   └── UIViewController (Dd7-d5&lt;span class="hljs-number"&gt;-3&lt;/span&gt;aK)
│
├── Tab &lt;span class="hljs-number"&gt;2&lt;/span&gt; — &lt;span class="hljs-string"&gt;"Add"&lt;/span&gt;   (plus icon)
│   └── UIViewController (tBp-mc-axm)
│
└── Tab &lt;span class="hljs-number"&gt;3&lt;/span&gt; — &lt;span class="hljs-string"&gt;"Item"&lt;/span&gt;  (gearshape icon) ← settings/gear
    └── UIViewController (gDx-nH&lt;span class="hljs-number"&gt;-5&lt;/span&gt;J7)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The three tabs are connected via &lt;code&gt;&amp;lt;segue kind=&amp;quot;relationship&amp;quot; relationship=&amp;quot;viewControllers&amp;quot;&amp;gt;&lt;/code&gt; — a special storyboard relationship that populates the tab bar&amp;#39;s &lt;code&gt;viewControllers&lt;/code&gt; array.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="iboutlet-connecting-storyboard-ui-to-code"&gt;IBOutlet — Connecting Storyboard UI to Code&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;@IBOutlet&lt;/code&gt; is how you create a &lt;strong&gt;reference from your Swift code to a UI element defined in the Storyboard&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// In LockScreenViewController.swift&lt;/span&gt;
&lt;span class="hljs-variable"&gt;@IBOutlet&lt;/span&gt; weak var &lt;span class="hljs-attribute"&gt;textField1&lt;/span&gt;: UITextField!   &lt;span class="hljs-comment"&gt;// digit 1&lt;/span&gt;
&lt;span class="hljs-variable"&gt;@IBOutlet&lt;/span&gt; weak var &lt;span class="hljs-attribute"&gt;textField2&lt;/span&gt;: UITextField!   &lt;span class="hljs-comment"&gt;// digit 2&lt;/span&gt;
&lt;span class="hljs-variable"&gt;@IBOutlet&lt;/span&gt; weak var &lt;span class="hljs-attribute"&gt;textField3&lt;/span&gt;: UITextField!   &lt;span class="hljs-comment"&gt;// digit 3&lt;/span&gt;
&lt;span class="hljs-variable"&gt;@IBOutlet&lt;/span&gt; weak var &lt;span class="hljs-attribute"&gt;textField4&lt;/span&gt;: UITextField!   &lt;span class="hljs-comment"&gt;// digit 4&lt;/span&gt;

&lt;span class="hljs-variable"&gt;@IBOutlet&lt;/span&gt; weak var &lt;span class="hljs-attribute"&gt;messageLabel&lt;/span&gt;: UILabel!     &lt;span class="hljs-comment"&gt;// status/welcome message&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The connection is stored in the storyboard XML &lt;code&gt;&amp;lt;connections&amp;gt;&lt;/code&gt; section:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-xml"&gt;&amp;lt;outlet &lt;span class="hljs-keyword"&gt;property&lt;/span&gt;=&lt;span class="hljs-string"&gt;"messageLabel"&lt;/span&gt; destination=&lt;span class="hljs-string"&gt;"8es-74-hrV"&lt;/span&gt; &lt;span class="hljs-built_in"&gt;id&lt;/span&gt;=&lt;span class="hljs-string"&gt;"ylD-M4-Bto"&lt;/span&gt;/&amp;gt;
&amp;lt;outlet &lt;span class="hljs-keyword"&gt;property&lt;/span&gt;=&lt;span class="hljs-string"&gt;"textField1"&lt;/span&gt;   destination=&lt;span class="hljs-string"&gt;"J9t-mY-Vbq"&lt;/span&gt; &lt;span class="hljs-built_in"&gt;id&lt;/span&gt;=&lt;span class="hljs-string"&gt;"0he-5t-ky5"&lt;/span&gt;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Xcode&amp;#39;s Interface Builder draws a line between the circle in the Swift editor margin and the UI element in the canvas to establish this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important notes about IBOutlets:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;weak&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The view controller doesn&amp;#39;t own the views — the view hierarchy does. &lt;code&gt;weak&lt;/code&gt; prevents a retain cycle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;!&lt;/code&gt; (implicitly unwrapped optional)&lt;/td&gt;
&lt;td&gt;The outlet is &lt;code&gt;nil&lt;/code&gt; before the storyboard loads. The &lt;code&gt;!&lt;/code&gt; means &amp;quot;I promise this won&amp;#39;t be nil when I use it.&amp;quot; If you access it before &lt;code&gt;viewDidLoad&lt;/code&gt;, it crashes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access timing&lt;/td&gt;
&lt;td&gt;All &lt;code&gt;@IBOutlet&lt;/code&gt; properties are set just before &lt;code&gt;viewDidLoad()&lt;/code&gt; is called. Never access them in &lt;code&gt;init&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Once connected, you update UI elements imperatively:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Updating a label&lt;/span&gt;
messageLabel&lt;span class="hljs-selector-class"&gt;.text&lt;/span&gt; = &lt;span class="hljs-string"&gt;"Enter your passcode to unlock secure room"&lt;/span&gt;
messageLabel&lt;span class="hljs-selector-class"&gt;.textColor&lt;/span&gt; = &lt;span class="hljs-selector-class"&gt;.systemRed&lt;/span&gt;
messageLabel&lt;span class="hljs-selector-class"&gt;.isHidden&lt;/span&gt; = true

&lt;span class="hljs-comment"&gt;// Updating a text field&lt;/span&gt;
textField1&lt;span class="hljs-selector-class"&gt;.text&lt;/span&gt; = &lt;span class="hljs-string"&gt;""&lt;/span&gt;
textField1&lt;span class="hljs-selector-class"&gt;.borderStyle&lt;/span&gt; = &lt;span class="hljs-selector-class"&gt;.roundedRect&lt;/span&gt;
textField1&lt;span class="hljs-selector-class"&gt;.backgroundColor&lt;/span&gt; = .systemGray6
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="ibaction-connecting-buttons-to-code"&gt;IBAction — Connecting Buttons to Code&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;@IBAction&lt;/code&gt; marks a method as callable from the Storyboard. When a user interaction event fires (e.g. &lt;code&gt;touchUpInside&lt;/code&gt; on a button), UIKit calls this method.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// In LockScreenViewController.swift&lt;/span&gt;

&lt;span class="hljs-comment"&gt;// sender: UIAction is the new iOS 15+ style using UIAction&lt;/span&gt;
&lt;span class="hljs-meta"&gt;@IBAction&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;verify&lt;/span&gt;&lt;span class="hljs-params"&gt;(sender: UIAction)&lt;/span&gt;&lt;/span&gt; {
    verifyOtp()
}

&lt;span class="hljs-comment"&gt;// Traditional UIKit style (also valid):&lt;/span&gt;
&lt;span class="hljs-meta"&gt;@IBAction&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;verify&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; sender: UIButton)&lt;/span&gt;&lt;/span&gt; {
    verifyOtp()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the storyboard XML this is:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-xml"&gt;&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;connections&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;action&lt;/span&gt; &lt;span class="hljs-attr"&gt;selector&lt;/span&gt;=&lt;span class="hljs-string"&gt;"verifyWithSender:"&lt;/span&gt; &lt;span class="hljs-attr"&gt;destination&lt;/span&gt;=&lt;span class="hljs-string"&gt;"Y6W-OH-hqX"&lt;/span&gt;
            &lt;span class="hljs-attr"&gt;eventType&lt;/span&gt;=&lt;span class="hljs-string"&gt;"touchUpInside"&lt;/span&gt; &lt;span class="hljs-attr"&gt;id&lt;/span&gt;=&lt;span class="hljs-string"&gt;"Y0A-Uq-W4Y"&lt;/span&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;connections&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;eventType=&amp;quot;touchUpInside&amp;quot;&lt;/code&gt; is the most common button event — fires when the user lifts their finger inside the button bounds. Other events: &lt;code&gt;touchDown&lt;/code&gt;, &lt;code&gt;valueChanged&lt;/code&gt; (for sliders/switches), &lt;code&gt;editingChanged&lt;/code&gt; (for text fields).&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="auto-layout-constraints"&gt;Auto Layout &amp;amp; Constraints&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Auto Layout&lt;/strong&gt; is UIKit&amp;#39;s constraint-based layout system. Instead of hardcoding pixel positions, you define &lt;strong&gt;rules&lt;/strong&gt; (constraints) that the system solves at runtime for any screen size.&lt;/p&gt;
&lt;p&gt;A constraint is a mathematical relationship between two layout attributes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;item1&lt;span class="hljs-selector-class"&gt;.attribute&lt;/span&gt; = multiplier × item2&lt;span class="hljs-selector-class"&gt;.attribute&lt;/span&gt; + constant
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Common constraint examples (as they appear in code):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Center horizontally in parent&lt;/span&gt;
NSLayoutConstraint(
    item: logoImageView,
    attribute: &lt;span class="hljs-selector-class"&gt;.centerX&lt;/span&gt;,
    relatedBy: &lt;span class="hljs-selector-class"&gt;.equal&lt;/span&gt;,
    toItem: view,
    attribute: &lt;span class="hljs-selector-class"&gt;.centerX&lt;/span&gt;,
    multiplier: &lt;span class="hljs-number"&gt;1.0&lt;/span&gt;,
    constant: &lt;span class="hljs-number"&gt;0&lt;/span&gt;
)&lt;span class="hljs-selector-class"&gt;.isActive&lt;/span&gt; = true

&lt;span class="hljs-comment"&gt;// Width = 50% of parent width (multiplier: 0.5)&lt;/span&gt;
logoImageView&lt;span class="hljs-selector-class"&gt;.widthAnchor&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.constraint&lt;/span&gt;(
    equalTo: view&lt;span class="hljs-selector-class"&gt;.widthAnchor&lt;/span&gt;,
    multiplier: &lt;span class="hljs-number"&gt;0.5&lt;/span&gt;
)&lt;span class="hljs-selector-class"&gt;.isActive&lt;/span&gt; = true

&lt;span class="hljs-comment"&gt;// Modern anchor syntax (preferred in code)&lt;/span&gt;
NSLayoutConstraint.activate([
    stackView&lt;span class="hljs-selector-class"&gt;.leadingAnchor&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.constraint&lt;/span&gt;(equalTo: view&lt;span class="hljs-selector-class"&gt;.safeAreaLayoutGuide&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.leadingAnchor&lt;/span&gt;, constant: &lt;span class="hljs-number"&gt;30&lt;/span&gt;),
    stackView&lt;span class="hljs-selector-class"&gt;.trailingAnchor&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.constraint&lt;/span&gt;(equalTo: view&lt;span class="hljs-selector-class"&gt;.safeAreaLayoutGuide&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.trailingAnchor&lt;/span&gt;, constant: -&lt;span class="hljs-number"&gt;30&lt;/span&gt;),
    stackView&lt;span class="hljs-selector-class"&gt;.topAnchor&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.constraint&lt;/span&gt;(equalTo: titleLabel&lt;span class="hljs-selector-class"&gt;.bottomAnchor&lt;/span&gt;, constant: &lt;span class="hljs-number"&gt;40&lt;/span&gt;)
])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Safe Area Layout Guide&lt;/strong&gt; — the area of the screen not covered by the notch, Dynamic Island, or Home indicator. Always constrain to &lt;code&gt;safeAreaLayoutGuide&lt;/code&gt; for content that must be fully visible.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Pin label to bottom safe area with 30pt margin&lt;/span&gt;
messageLabel&lt;span class="hljs-selector-class"&gt;.bottomAnchor&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.constraint&lt;/span&gt;(
    equalTo: view&lt;span class="hljs-selector-class"&gt;.safeAreaLayoutGuide&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.bottomAnchor&lt;/span&gt;,
    constant: -&lt;span class="hljs-number"&gt;30&lt;/span&gt;
)&lt;span class="hljs-selector-class"&gt;.isActive&lt;/span&gt; = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Critical rule for programmatic views:&lt;/strong&gt; Any view you create in code (not from storyboard) must have this set before adding constraints:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;myView&lt;span class="hljs-selector-class"&gt;.translatesAutoresizingMaskIntoConstraints&lt;/span&gt; = false
&lt;span class="hljs-comment"&gt;// Without this, Auto Layout and the old autoresizingMask system conflict → broken layout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="uistackview"&gt;UIStackView&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;UIStackView&lt;/code&gt; is a layout container that arranges its &lt;code&gt;arrangedSubviews&lt;/code&gt; either horizontally or vertically — automatically managing spacing and alignment. It is the UIKit equivalent of SwiftUI&amp;#39;s &lt;code&gt;HStack&lt;/code&gt;/&lt;code&gt;VStack&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the LockScreen storyboard, all four pin digit text fields are inside a &lt;code&gt;UIStackView&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-xml"&gt;&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;stackView&lt;/span&gt; &lt;span class="hljs-attr"&gt;distribution&lt;/span&gt;=&lt;span class="hljs-string"&gt;"fillEqually"&lt;/span&gt; &lt;span class="hljs-attr"&gt;spacing&lt;/span&gt;=&lt;span class="hljs-string"&gt;"20"&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;subviews&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;textField&lt;/span&gt; &lt;span class="hljs-attr"&gt;id&lt;/span&gt;=&lt;span class="hljs-string"&gt;"J9t-mY-Vbq"&lt;/span&gt;/&amp;gt;&lt;/span&gt; &lt;span class="hljs-comment"&gt;&amp;lt;!-- digit 1 --&amp;gt;&lt;/span&gt;
        &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;textField&lt;/span&gt; &lt;span class="hljs-attr"&gt;id&lt;/span&gt;=&lt;span class="hljs-string"&gt;"51S-e9-Mi9"&lt;/span&gt;/&amp;gt;&lt;/span&gt; &lt;span class="hljs-comment"&gt;&amp;lt;!-- digit 2 --&amp;gt;&lt;/span&gt;
        &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;textField&lt;/span&gt; &lt;span class="hljs-attr"&gt;id&lt;/span&gt;=&lt;span class="hljs-string"&gt;"28d-qL-eN1"&lt;/span&gt;/&amp;gt;&lt;/span&gt; &lt;span class="hljs-comment"&gt;&amp;lt;!-- digit 3 --&amp;gt;&lt;/span&gt;
        &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;textField&lt;/span&gt; &lt;span class="hljs-attr"&gt;id&lt;/span&gt;=&lt;span class="hljs-string"&gt;"3o3-O4-NwI"&lt;/span&gt;/&amp;gt;&lt;/span&gt; &lt;span class="hljs-comment"&gt;&amp;lt;!-- digit 4 --&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;subviews&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;stackView&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Creating UIStackView in code:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;let stackView = UIStackView(arrangedSubviews: [tf1, tf2, tf3, tf4])
stackView&lt;span class="hljs-selector-class"&gt;.axis&lt;/span&gt; = &lt;span class="hljs-selector-class"&gt;.horizontal&lt;/span&gt;           &lt;span class="hljs-comment"&gt;// .vertical for vertical stack&lt;/span&gt;
stackView&lt;span class="hljs-selector-class"&gt;.distribution&lt;/span&gt; = &lt;span class="hljs-selector-class"&gt;.fillEqually&lt;/span&gt;  &lt;span class="hljs-comment"&gt;// all arranged views get equal width&lt;/span&gt;
stackView&lt;span class="hljs-selector-class"&gt;.spacing&lt;/span&gt; = &lt;span class="hljs-number"&gt;20&lt;/span&gt;                 &lt;span class="hljs-comment"&gt;// 20pt gap between each view&lt;/span&gt;
stackView&lt;span class="hljs-selector-class"&gt;.translatesAutoresizingMaskIntoConstraints&lt;/span&gt; = false
view.addSubview(stackView)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;distribution&lt;/code&gt; options:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.fill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;First subview fills available space; others use their intrinsic size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.fillEqually&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All subviews get the same size — perfect for a pin pad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.equalSpacing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Equal spacing between views; views use intrinsic size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.equalCentering&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Centers of views are equally spaced&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="controllers-layer-uiviewcontroller"&gt;Controllers Layer — UIViewController&lt;/h2&gt;
&lt;h3 id="the-uiviewcontroller-lifecycle"&gt;The UIViewController Lifecycle&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;UIViewController&lt;/code&gt; is the backbone of every UIKit screen. It manages a view hierarchy and responds to system events. Every screen is a &lt;code&gt;UIViewController&lt;/code&gt; subclass.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                    ┌─────────────────────────────────┐
                    │       init / loadView            │  ← View created from storyboard
                    └──────────────┬──────────────────┘
                                   │
                    ┌──────────────▼──────────────────┐
                    │         viewDidLoad()            │  ← Called ONCE after view loads
                    │   ✅ &lt;span class="hljs-keyword"&gt;Set&lt;/span&gt; up delegates            │     &lt;span class="hljs-keyword"&gt;Safe&lt;/span&gt; &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; &lt;span class="hljs-keyword"&gt;access&lt;/span&gt; @IBOutlets here
                    │   ✅ Configure UI               │
                    │   ✅ &lt;span class="hljs-keyword"&gt;Add&lt;/span&gt; gesture recognisers     │
                    └──────────────┬──────────────────┘
                                   │
                    ┌──────────────▼──────────────────┐
                    │         viewWillAppear()         │  ← &lt;span class="hljs-keyword"&gt;Before&lt;/span&gt; &lt;span class="hljs-keyword"&gt;view&lt;/span&gt; becomes &lt;span class="hljs-keyword"&gt;visible&lt;/span&gt;
                    │   ✅ &lt;span class="hljs-keyword"&gt;Refresh&lt;/span&gt; &lt;span class="hljs-keyword"&gt;data&lt;/span&gt;               │     Called every &lt;span class="hljs-keyword"&gt;time&lt;/span&gt; (&lt;span class="hljs-keyword"&gt;not&lt;/span&gt; just once)
                    │   ✅ &lt;span class="hljs-keyword"&gt;Start&lt;/span&gt; animations           │
                    └──────────────┬──────────────────┘
                                   │
                    ┌──────────────▼──────────────────┐
                    │         viewDidAppear()          │  ← &lt;span class="hljs-keyword"&gt;View&lt;/span&gt; &lt;span class="hljs-keyword"&gt;is&lt;/span&gt; fully &lt;span class="hljs-keyword"&gt;visible&lt;/span&gt;
                    │   ✅ &lt;span class="hljs-keyword"&gt;Start&lt;/span&gt; expensive &lt;span class="hljs-keyword"&gt;operations&lt;/span&gt;  │
                    │   ✅ &lt;span class="hljs-keyword"&gt;Trigger&lt;/span&gt; onboarding flows   │
                    └──────────────┬──────────────────┘
                                   │  (&lt;span class="hljs-keyword"&gt;user&lt;/span&gt; navigates away)
                    ┌──────────────▼──────────────────┐
                    │         viewWillDisappear()      │  ← About &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; hide
                    │   ✅ &lt;span class="hljs-keyword"&gt;Save&lt;/span&gt; &lt;span class="hljs-keyword"&gt;user&lt;/span&gt; &lt;span class="hljs-keyword"&gt;input&lt;/span&gt;            │
                    │   ✅ &lt;span class="hljs-keyword"&gt;Stop&lt;/span&gt; timers                │
                    └──────────────┬──────────────────┘
                                   │
                    ┌──────────────▼──────────────────┐
                    │         viewDidDisappear()       │  ← Fully hidden
                    └──────────────┬──────────────────┘
                                   │  (&lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;memory&lt;/span&gt; pressure)
                    ┌──────────────▼──────────────────┐
                    │         deinit                   │
                    └─────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Key rule:&lt;/strong&gt; &lt;code&gt;super.viewDidLoad()&lt;/code&gt; must always be called first. All Xcode templates include this. Forgetting it causes subtle bugs because the parent class performs essential setup.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="lockscreenviewcontroller-swift"&gt;LockScreenViewController.swift&lt;/h3&gt;
&lt;p&gt;This is the most complete file in the project — it demonstrates nearly every core UIKit concept.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; UIKit

&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;LockScreenViewController&lt;/span&gt;: &lt;span class="hljs-title"&gt;UIViewController&lt;/span&gt;, &lt;span class="hljs-title"&gt;UITextFieldDelegate&lt;/span&gt; &lt;/span&gt;{

    &lt;span class="hljs-comment"&gt;// ── IBOutlets ────────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-meta"&gt;@IBOutlet&lt;/span&gt; &lt;span class="hljs-keyword"&gt;weak&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; textField1: &lt;span class="hljs-type"&gt;UITextField&lt;/span&gt;!
    &lt;span class="hljs-meta"&gt;@IBOutlet&lt;/span&gt; &lt;span class="hljs-keyword"&gt;weak&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; textField2: &lt;span class="hljs-type"&gt;UITextField&lt;/span&gt;!
    &lt;span class="hljs-meta"&gt;@IBOutlet&lt;/span&gt; &lt;span class="hljs-keyword"&gt;weak&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; textField3: &lt;span class="hljs-type"&gt;UITextField&lt;/span&gt;!
    &lt;span class="hljs-meta"&gt;@IBOutlet&lt;/span&gt; &lt;span class="hljs-keyword"&gt;weak&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; textField4: &lt;span class="hljs-type"&gt;UITextField&lt;/span&gt;!

    &lt;span class="hljs-meta"&gt;@IBOutlet&lt;/span&gt; &lt;span class="hljs-keyword"&gt;weak&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; messageLabel: &lt;span class="hljs-type"&gt;UILabel&lt;/span&gt;!

    &lt;span class="hljs-comment"&gt;// ── IBActions ────────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-meta"&gt;@IBAction&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;verify&lt;/span&gt;&lt;span class="hljs-params"&gt;(sender: UIAction)&lt;/span&gt;&lt;/span&gt; {
        verifyOtp()
    }

    &lt;span class="hljs-meta"&gt;@IBAction&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;setPassword&lt;/span&gt;&lt;span class="hljs-params"&gt;(sender: UIAction)&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-comment"&gt;// Hardcoded for development — saves "4321" as the passcode&lt;/span&gt;
        &lt;span class="hljs-type"&gt;KeychainManager&lt;/span&gt;.save(key: passcodeKey, value: &lt;span class="hljs-string"&gt;"4321"&lt;/span&gt;)
    }

    &lt;span class="hljs-comment"&gt;// ── viewDidLoad ──────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;viewDidLoad&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;super&lt;/span&gt;.viewDidLoad()

        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; fields = [textField1, textField2, textField3, textField4]

        fields.forEach {
            $&lt;span class="hljs-number"&gt;0&lt;/span&gt;?.delegate = &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;  &lt;span class="hljs-comment"&gt;// set this VC as the delegate for all 4 fields&lt;/span&gt;
            &lt;span class="hljs-comment"&gt;// addTarget: target-action pattern — calls textDidChange when text changes&lt;/span&gt;
            $&lt;span class="hljs-number"&gt;0&lt;/span&gt;?.addTarget(&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;, action: #selector(textDidChange(&lt;span class="hljs-number"&gt;_&lt;/span&gt;:)), &lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: .editingChanged)
        }

        &lt;span class="hljs-comment"&gt;// Tap anywhere on background to dismiss keyboard&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; uiTap = &lt;span class="hljs-type"&gt;UIGestureRecognizer&lt;/span&gt;(target: &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;, action: #selector(dismissKeyboard))
        view.addGestureRecognizer(uiTap)

        &lt;span class="hljs-comment"&gt;// Show first field keyboard immediately&lt;/span&gt;
        textField1.becomeFirstResponder()

        &lt;span class="hljs-comment"&gt;// Contextual welcome message&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-type"&gt;KeychainManager&lt;/span&gt;.read(key: passcodeKey) == &lt;span class="hljs-literal"&gt;nil&lt;/span&gt; {
            messageLabel.text = &lt;span class="hljs-string"&gt;"Welcome &#128591; create a passcode"&lt;/span&gt;
        } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
            messageLabel.text = &lt;span class="hljs-string"&gt;"Enter your passcode to unlock secure room"&lt;/span&gt;
        }
    }

    &lt;span class="hljs-comment"&gt;// ── Passcode Verification Logic ──────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;verifyOtp&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; otp = &lt;span class="hljs-string"&gt;"&lt;span class="hljs-subst"&gt;\(textField1.text ?? "")&lt;/span&gt;&lt;span class="hljs-subst"&gt;\(textField2.text ?? "")&lt;/span&gt;&lt;span class="hljs-subst"&gt;\(textField3.text ?? "")&lt;/span&gt;&lt;span class="hljs-subst"&gt;\(textField4.text ?? "")&lt;/span&gt;"&lt;/span&gt;

        &lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; otp.&lt;span class="hljs-built_in"&gt;count&lt;/span&gt; == &lt;span class="hljs-number"&gt;4&lt;/span&gt; &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
            showAlert(msg: &lt;span class="hljs-string"&gt;"Please enter complete passcode"&lt;/span&gt;)
            &lt;span class="hljs-keyword"&gt;return&lt;/span&gt;
        }

        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; savedPass = &lt;span class="hljs-type"&gt;KeychainManager&lt;/span&gt;.read(key: passcodeKey) {
            &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; savedPass == otp {
                goToHome()
            } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
                showAlert(msg: &lt;span class="hljs-string"&gt;"Incorrect passcode"&lt;/span&gt;)
                clearFields()
            }
        } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
            &lt;span class="hljs-comment"&gt;// First launch: no passcode exists yet — register mode&lt;/span&gt;
        }
    }

    &lt;span class="hljs-comment"&gt;// ── Alert ────────────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;showAlert&lt;/span&gt;&lt;span class="hljs-params"&gt;(msg: String)&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; alert = &lt;span class="hljs-type"&gt;UIAlertController&lt;/span&gt;(title: &lt;span class="hljs-string"&gt;"Error"&lt;/span&gt;, message: msg, preferredStyle: .alert)
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; okAction = &lt;span class="hljs-type"&gt;UIAlertAction&lt;/span&gt;(title: &lt;span class="hljs-string"&gt;"OK"&lt;/span&gt;, style: .&lt;span class="hljs-keyword"&gt;default&lt;/span&gt;, handler: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;)
        alert.addAction(okAction)
        present(alert, animated: &lt;span class="hljs-literal"&gt;true&lt;/span&gt;, completion: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;)
    }

    &lt;span class="hljs-comment"&gt;// ── Keyboard ─────────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-meta"&gt;@objc&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;dismissKeyboard&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        view.endEditing(&lt;span class="hljs-literal"&gt;true&lt;/span&gt;)  &lt;span class="hljs-comment"&gt;// tells every text field in the view to resign first responder&lt;/span&gt;
    }

    &lt;span class="hljs-comment"&gt;// ── UITextFieldDelegate — auto-advance &amp;amp; auto-backspace ──────&lt;/span&gt;
    &lt;span class="hljs-meta"&gt;@objc&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;textDidChange&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; textField: UITextField)&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; text = textField.text, !text.isEmpty &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; }

        &lt;span class="hljs-comment"&gt;// Auto-advance: move focus to next field when a digit is entered&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField1 {
            textField2.becomeFirstResponder()
        } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField2 {
            textField3.becomeFirstResponder()
        } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField3 {
            textField4.becomeFirstResponder()
        } &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField4 {
            &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField.text?.isEmpty == &lt;span class="hljs-literal"&gt;false&lt;/span&gt; {
                verifyOtp()
                dismissKeyboard()
            }
        }
    }

    &lt;span class="hljs-comment"&gt;// Called BEFORE a character is inserted or deleted&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;// Returns true = allow the change, false = block it&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;textField&lt;/span&gt;&lt;span class="hljs-params"&gt;(
        &lt;span class="hljs-number"&gt;_&lt;/span&gt; textField: UITextField,
        shouldChangeCharactersIn range: NSRange,
        replacementString string: String
    )&lt;/span&gt;&lt;/span&gt; -&amp;gt; &lt;span class="hljs-type"&gt;Bool&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; string.isEmpty {
            &lt;span class="hljs-comment"&gt;// Backspace: move focus to previous field&lt;/span&gt;
            &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField2 { textField1.becomeFirstResponder() }
            &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField3 { textField2.becomeFirstResponder() }
            &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField4 { textField3.becomeFirstResponder() }

            textField.text = &lt;span class="hljs-string"&gt;""&lt;/span&gt;
            &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-literal"&gt;false&lt;/span&gt;   &lt;span class="hljs-comment"&gt;// block the default deletion (we already cleared manually)&lt;/span&gt;
        }

        &lt;span class="hljs-comment"&gt;// Only allow one character per field: if already has text, reject new input&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; textField.text?.isEmpty ?? &lt;span class="hljs-literal"&gt;true&lt;/span&gt;
    }

    &lt;span class="hljs-comment"&gt;// ── Helpers ──────────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;clearFields&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        [textField1, textField2, textField3, textField4].forEach {
            $&lt;span class="hljs-number"&gt;0&lt;/span&gt;?.text = &lt;span class="hljs-string"&gt;""&lt;/span&gt;
        }
        textField1.becomeFirstResponder()
    }

    &lt;span class="hljs-comment"&gt;// ── Navigation ───────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;goToHome&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-comment"&gt;// Get SceneDelegate to access the window object&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; sceneDelegate = view.window?.windowScene?.delegate &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;? &lt;span class="hljs-type"&gt;SceneDelegate&lt;/span&gt; &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
            &lt;span class="hljs-keyword"&gt;return&lt;/span&gt;
        }

        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; storyboard = &lt;span class="hljs-type"&gt;UIStoryboard&lt;/span&gt;(name: &lt;span class="hljs-string"&gt;"HomeScreen"&lt;/span&gt;, bundle: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;)
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; homeVc = storyboard.instantiateInitialViewController()

        &lt;span class="hljs-type"&gt;DispatchQueue&lt;/span&gt;.main.async {
            sceneDelegate.window?.rootViewController = homeVc
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="homeviewcontroller-swift"&gt;HomeViewController.swift&lt;/h3&gt;
&lt;p&gt;The home view controller is currently a scaffold — it demonstrates the minimum valid &lt;code&gt;UIViewController&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; UIKit

&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;HomeViewController&lt;/span&gt;: &lt;span class="hljs-title"&gt;UIViewController&lt;/span&gt; &lt;/span&gt;{

    &lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;viewDidLoad&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;super&lt;/span&gt;.viewDidLoad()
        &lt;span class="hljs-comment"&gt;// UI setup code goes here&lt;/span&gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is intentional. In a production app, &lt;code&gt;HomeViewController&lt;/code&gt; would likely contain a &lt;code&gt;UITableView&lt;/code&gt; or &lt;code&gt;UICollectionView&lt;/code&gt; showing the stored secrets, with &lt;code&gt;NSFetchedResultsController&lt;/code&gt; feeding data from Core Data.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="navigation-in-uikit"&gt;Navigation in UIKit&lt;/h2&gt;
&lt;p&gt;UIKit has several navigation patterns. SecureRoom uses the most powerful one: &lt;strong&gt;directly swapping &lt;code&gt;window.rootViewController&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="programmatic-navigation-via-uiwindow"&gt;Programmatic Navigation via UIWindow&lt;/h3&gt;
&lt;p&gt;Swapping &lt;code&gt;window.rootViewController&lt;/code&gt; is the &lt;strong&gt;nuclear option&lt;/strong&gt; — it completely replaces everything on screen. It&amp;#39;s perfect for authentication flows where you never want the user to be able to swipe back.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// From LockScreenViewController — navigate to home after successful PIN&lt;/span&gt;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;goToHome&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; sceneDelegate = view.window?.windowScene?.delegate &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;? &lt;span class="hljs-type"&gt;SceneDelegate&lt;/span&gt; &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt;
    }

    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; storyboard = &lt;span class="hljs-type"&gt;UIStoryboard&lt;/span&gt;(name: &lt;span class="hljs-string"&gt;"HomeScreen"&lt;/span&gt;, bundle: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;)
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; homeVc = storyboard.instantiateInitialViewController()

    &lt;span class="hljs-type"&gt;DispatchQueue&lt;/span&gt;.main.async {
        sceneDelegate.window?.rootViewController = homeVc
        &lt;span class="hljs-comment"&gt;// Optional: add a transition animation&lt;/span&gt;
        &lt;span class="hljs-comment"&gt;// UIView.transition(with: sceneDelegate.window!, duration: 0.3,&lt;/span&gt;
        &lt;span class="hljs-comment"&gt;//                   options: .transitionCrossDissolve, animations: nil)&lt;/span&gt;
    }
}

&lt;span class="hljs-comment"&gt;// From SceneDelegate — lock screen on background&lt;/span&gt;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;lockScreen&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; storyboard = &lt;span class="hljs-type"&gt;UIStoryboard&lt;/span&gt;(name: &lt;span class="hljs-string"&gt;"LockScreen"&lt;/span&gt;, bundle: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;)
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; lockVc = storyboard.instantiateInitialViewController()

    &lt;span class="hljs-type"&gt;DispatchQueue&lt;/span&gt;.main.async {
        &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.window?.rootViewController = lockVc
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Access chain:&lt;/strong&gt; &lt;code&gt;view.window?.windowScene?.delegate as? SceneDelegate&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIViewController.view     ← the ViewControlle&lt;span class="hljs-string"&gt;r's root UIView
        │ .window
UIWindow                  ← the window that contains the view
        │ .windowScene
UIWindowScene             ← the scene (multi-window support)
        │ .delegate
UIWindowSceneDelegate     ← the scene'&lt;/span&gt;s delegate (cast to SceneDelegate)
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h3 id="uinavigationcontroller"&gt;UINavigationController&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;UINavigationController&lt;/code&gt; manages a &lt;strong&gt;stack&lt;/strong&gt; of view controllers with a navigation bar and back button. This is the standard push/pop navigation pattern.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Push — adds a new VC to the top of the stack (slides in from right)&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; detailVC = &lt;span class="hljs-type"&gt;DetailViewController&lt;/span&gt;()
navigationController?.pushViewController(detailVC, animated: &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)

&lt;span class="hljs-comment"&gt;// Pop — removes the top VC (slides back left)&lt;/span&gt;
navigationController?.popViewController(animated: &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)

&lt;span class="hljs-comment"&gt;// Pop to root — removes everything except the first VC&lt;/span&gt;
navigationController?.popToRootViewController(animated: &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)

&lt;span class="hljs-comment"&gt;// Passing data forward — set properties before pushing&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; detailVC = &lt;span class="hljs-type"&gt;DetailViewController&lt;/span&gt;()
detailVC.secretTitle = &lt;span class="hljs-string"&gt;"My Password"&lt;/span&gt;
navigationController?.pushViewController(detailVC, animated: &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)

&lt;span class="hljs-comment"&gt;// Passing data back — use a delegate protocol or closure&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;ListViewController&lt;/span&gt;: &lt;span class="hljs-title"&gt;UIViewController&lt;/span&gt;, &lt;span class="hljs-title"&gt;DetailDelegate&lt;/span&gt; &lt;/span&gt;{
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;didUpdateSecret&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; secret: SecretModel)&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-comment"&gt;// handle the update&lt;/span&gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="uitabbarcontroller"&gt;UITabBarController&lt;/h3&gt;
&lt;p&gt;From the &lt;code&gt;HomeScreen.storyboard&lt;/code&gt;, the app uses a &lt;code&gt;UITabBarController&lt;/code&gt; with three tabs. This is the standard pattern for apps with distinct top-level sections.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;// Programmatic setup (alternative to Storyboard)
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-attr"&gt;tabBarController&lt;/span&gt; = UITabBarController()

&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-attr"&gt;homeVC&lt;/span&gt; = HomeViewController()
homeVC.&lt;span class="hljs-attr"&gt;tabBarItem&lt;/span&gt; = UITabBarItem(
    title: &lt;span class="hljs-string"&gt;"Home"&lt;/span&gt;,
    image: UIImage(systemName: &lt;span class="hljs-string"&gt;"house.circle"&lt;/span&gt;),
    selectedImage: UIImage(systemName: &lt;span class="hljs-string"&gt;"house.circle.fill"&lt;/span&gt;)
)

&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-attr"&gt;addVC&lt;/span&gt; = AddViewController()
addVC.&lt;span class="hljs-attr"&gt;tabBarItem&lt;/span&gt; = UITabBarItem(
    title: &lt;span class="hljs-string"&gt;"Add"&lt;/span&gt;,
    image: UIImage(systemName: &lt;span class="hljs-string"&gt;"plus"&lt;/span&gt;),
    tag: &lt;span class="hljs-number"&gt;1&lt;/span&gt;
)

&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-attr"&gt;settingsVC&lt;/span&gt; = SettingsViewController()
settingsVC.&lt;span class="hljs-attr"&gt;tabBarItem&lt;/span&gt; = UITabBarItem(
    tabBarSystemItem: .more,
    tag: &lt;span class="hljs-number"&gt;2&lt;/span&gt;
)

tabBarController.&lt;span class="hljs-attr"&gt;viewControllers&lt;/span&gt; = [homeVC, addVC, settingsVC]
window?.&lt;span class="hljs-attr"&gt;rootViewController&lt;/span&gt; = tabBarController
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each tab can independently wrap its own &lt;code&gt;UINavigationController&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;tabBarController.viewControllers = [
    UINavigationController(&lt;span class="hljs-string"&gt;rootViewController:&lt;/span&gt; homeVC),
    UINavigationController(&lt;span class="hljs-string"&gt;rootViewController:&lt;/span&gt; addVC),
    UINavigationController(&lt;span class="hljs-string"&gt;rootViewController:&lt;/span&gt; settingsVC)
]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="segues"&gt;Segues&lt;/h3&gt;
&lt;p&gt;Segues are Storyboard-based transitions between view controllers. Though SecureRoom uses manual &lt;code&gt;rootViewController&lt;/code&gt; swaps, segues are the most common approach in storyboard-heavy apps.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Trigger a segue programmatically&lt;/span&gt;
performSegue(withIdentifier: &lt;span class="hljs-string"&gt;"showDetail"&lt;/span&gt;, sender: &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;)

&lt;span class="hljs-comment"&gt;// Prepare data before the segue fires (called automatically before every segue)&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;prepare&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt; segue: UIStoryboardSegue, sender: Any?)&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; segue.identifier == &lt;span class="hljs-string"&gt;"showDetail"&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; destination = segue.destination &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;! &lt;span class="hljs-type"&gt;DetailViewController&lt;/span&gt;
        destination.secret = selectedSecret  &lt;span class="hljs-comment"&gt;// pass data forward&lt;/span&gt;
    }
}

&lt;span class="hljs-comment"&gt;// Unwind segue — go back without data (define in destination VC)&lt;/span&gt;
&lt;span class="hljs-meta"&gt;@IBAction&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;unwindToHome&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; segue: UIStoryboardSegue)&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-comment"&gt;// called when the segue unwinds to this VC&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Segue types:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;show&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Push on NavigationController stack, or modal on others&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;showDetail&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;iPad: shows in detail pane; iPhone: push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;present modally&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Slides up as a modal sheet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;present as popover&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;iPad: popover bubble; iPhone: modal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unwind&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Goes back through the hierarchy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="helpers-layer"&gt;Helpers Layer&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Helpers/&lt;/code&gt; folder holds utility classes and constants that don&amp;#39;t belong to any single screen. This is one of the key separations that keeps ViewControllers lean.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="constants-swift"&gt;Constants.swift&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;// A file-scope &lt;span class="hljs-keyword"&gt;global&lt;/span&gt; constant — accessible everywhere &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; the &lt;span class="hljs-keyword"&gt;module&lt;/span&gt; without &lt;span class="hljs-keyword"&gt;import&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; passcodeKey: &lt;span class="hljs-built_in"&gt;String&lt;/span&gt; = &lt;span class="hljs-string"&gt;"passcode"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the &lt;strong&gt;Keychain key&lt;/strong&gt; used to store and retrieve the passcode. Defining it as a global constant instead of a string literal prevents typos — if you mistype &lt;code&gt;passcodeKy&lt;/code&gt; in Constants.swift, the compiler catches it immediately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Best practice pattern — group related constants in an enum namespace:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Better pattern for larger apps — prevents global namespace pollution&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;enum&lt;/span&gt; Keys {
    &lt;span class="hljs-keyword"&gt;static&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; passcode = &lt;span class="hljs-string"&gt;"passcode"&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;static&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; biometricEnabled = &lt;span class="hljs-string"&gt;"biometric_enabled"&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;static&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; lastLockTime = &lt;span class="hljs-string"&gt;"last_lock_time"&lt;/span&gt;
}

&lt;span class="hljs-comment"&gt;// Usage&lt;/span&gt;
KeychainManager.save(key: Keys.passcode, &lt;span class="hljs-keyword"&gt;value&lt;/span&gt;: &lt;span class="hljs-string"&gt;"1234"&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="keychainmanager-swift-ios-keychain-api"&gt;KeychainManager.swift — iOS Keychain API&lt;/h3&gt;
&lt;p&gt;The Keychain is iOS&amp;#39;s &lt;strong&gt;hardware-backed secure storage&lt;/strong&gt;. Unlike &lt;code&gt;UserDefaults&lt;/code&gt; (which stores data in plain text in a &lt;code&gt;.plist&lt;/code&gt; file), Keychain data is encrypted at rest and protected by the device&amp;#39;s Secure Enclave.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; Security
&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; Foundation

&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;KeychainManager&lt;/span&gt; &lt;/span&gt;{

    &lt;span class="hljs-comment"&gt;// ── SAVE ─────────────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;static&lt;/span&gt; func save(key: &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;span class="hljs-attr"&gt;value&lt;/span&gt;: &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;) -&amp;gt; Bool {
        &lt;span class="hljs-comment"&gt;// Convert String to raw bytes&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; data = value.data(using: .utf8)!

        &lt;span class="hljs-comment"&gt;// Build the query dictionary — kSec constants are CFString keys from Security.framework&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; query: [&lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: Any] = [
            kSecClass &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: kSecClassGenericPassword,  &lt;span class="hljs-comment"&gt;// "generic password" item type&lt;/span&gt;
            kSecAttrAccount &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: key,                 &lt;span class="hljs-comment"&gt;// the key (like a dictionary key)&lt;/span&gt;
            kSecValueData &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: data,                  &lt;span class="hljs-comment"&gt;// the value (raw bytes)&lt;/span&gt;
            kSecAttrAccessible &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: kSecAttrAccessibleWhenUnlocked
            &lt;span class="hljs-comment"&gt;// ↑ "accessible when device is unlocked" — most common security level&lt;/span&gt;
        ]

        &lt;span class="hljs-comment"&gt;// Delete any existing item first (update = delete + insert in Keychain API)&lt;/span&gt;
        SecItemDelete(query &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; CFDictionary)

        &lt;span class="hljs-comment"&gt;// Add the new item&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; status = SecItemAdd(query &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; CFDictionary, nil)
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; status == errSecSuccess
    }

    &lt;span class="hljs-comment"&gt;// ── READ ─────────────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;static&lt;/span&gt; func read(key: &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;) -&amp;gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;? {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; query: [&lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: Any] = [
            kSecClass &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: kSecClassGenericPassword,
            kSecAttrAccount &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: key,
            kSecReturnData &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: &lt;span class="hljs-literal"&gt;true&lt;/span&gt;,         &lt;span class="hljs-comment"&gt;// return the raw data&lt;/span&gt;
            kSecMatchLimit &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: kSecMatchLimitOne  &lt;span class="hljs-comment"&gt;// return at most 1 result&lt;/span&gt;
        ]

        &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; dataTypeRef: AnyObject?
        &lt;span class="hljs-comment"&gt;// SecItemCopyMatching writes result into dataTypeRef via inout pointer&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; status = SecItemCopyMatching(query &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; CFDictionary, &amp;amp;dataTypeRef)

        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; status == errSecSuccess,
           &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; data = dataTypeRef &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;? Data,
           &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; string = &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;(data: data, &lt;span class="hljs-attr"&gt;encoding&lt;/span&gt;: .utf8) {
            &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; string
        }

        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; nil  &lt;span class="hljs-comment"&gt;// key not found or decode failed&lt;/span&gt;
    }

    &lt;span class="hljs-comment"&gt;// ── DELETE ────────────────────────────────────────────────────&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;static&lt;/span&gt; func &lt;span class="hljs-keyword"&gt;delete&lt;/span&gt;(key: &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;) {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; query: [&lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: Any] = [
            kSecClass &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: kSecClassGenericPassword,
            kSecAttrAccount &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;: key
        ]
        SecItemDelete(query &lt;span class="hljs-keyword"&gt;as&lt;/span&gt; CFDictionary)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="keychain-concepts-in-depth"&gt;Keychain concepts in depth&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Security&lt;/code&gt; framework&lt;/td&gt;
&lt;td&gt;Low-level Apple framework for cryptography, Keychain, certificates. Imported with &lt;code&gt;import Security&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kSecClass&lt;/code&gt; / &lt;code&gt;kSecClassGenericPassword&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tells Keychain this is a generic password item (as opposed to an internet password, certificate, key, etc.).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kSecAttrAccount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &amp;quot;username&amp;quot; field — here repurposed as the key name.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kSecValueData&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The raw &lt;code&gt;Data&lt;/code&gt; blob to store. Encrypted at rest by the OS.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kSecAttrAccessible&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Determines when the item is accessible. &lt;code&gt;kSecAttrAccessibleWhenUnlocked&lt;/code&gt; = readable when device is unlocked; wiped on device restore without backup.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CFDictionary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Core Foundation dictionary type. The Keychain API predates Swift, so it requires &lt;code&gt;as CFDictionary&lt;/code&gt; casts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SecItemAdd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inserts a new Keychain item. Returns &lt;code&gt;OSStatus&lt;/code&gt; (an integer status code).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SecItemCopyMatching&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Queries Keychain and returns matching items. The &lt;code&gt;&amp;amp;dataTypeRef&lt;/code&gt; is an inout &lt;code&gt;UnsafeMutablePointer&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SecItemDelete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deletes matching Keychain items.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;errSecSuccess&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;OSStatus&lt;/code&gt; value 0 — means the operation succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;as String: kSecClass as String&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kSecClass&lt;/code&gt; is typed as &lt;code&gt;CFString&lt;/code&gt;. Cast to &lt;code&gt;String&lt;/code&gt; to use as a Swift dictionary key.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="keychain-vs-userdefaults"&gt;Keychain vs UserDefaults&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Keychain&lt;/th&gt;
&lt;th&gt;UserDefaults&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Encrypted SQLite, Secure Enclave backed&lt;/td&gt;
&lt;td&gt;Plain &lt;code&gt;.plist&lt;/code&gt; XML file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hardware encrypted, survives app reinstall&lt;/td&gt;
&lt;td&gt;Cleared on app delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Passwords, tokens, sensitive data&lt;/td&gt;
&lt;td&gt;Settings, preferences, non-sensitive state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complex C API (via Security framework)&lt;/td&gt;
&lt;td&gt;Simple &lt;code&gt;set(_:forKey:)&lt;/code&gt; / &lt;code&gt;string(forKey:)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iCloud sync&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Opt-in via &lt;code&gt;kSecAttrSynchronizable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not available&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="models-layer"&gt;Models Layer&lt;/h2&gt;
&lt;h3 id="secret-swift"&gt;Secret.swift&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;import Foundation

&lt;span class="hljs-comment"&gt;// A simple value type to represent a stored secret&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; SecretModel: Codable {
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-built_in"&gt;title&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;String&lt;/span&gt;   &lt;span class="hljs-comment"&gt;// e.g. "Gmail password"&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; value: &lt;span class="hljs-keyword"&gt;String&lt;/span&gt;   &lt;span class="hljs-comment"&gt;// e.g. "hunter2"&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This follows the same principles as SwiftUI models:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;struct&lt;/code&gt; (value type) — safe to pass around and copy; no reference counting&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Codable&lt;/code&gt; — can be encoded to JSON (&lt;code&gt;Encodable&lt;/code&gt;) and decoded from JSON (&lt;code&gt;Decodable&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;No UIKit imports — fully portable, testable in isolation&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Foundation&lt;/code&gt; only — the minimum necessary import&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;How this model would be used with Core Data:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In a production app, &lt;code&gt;SecretModel&lt;/code&gt; would complement a Core Data Entity. The entity stores data on disk; the struct serves as a lightweight in-memory representation:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Convert CoreData entity → Swift struct (the "DTO" pattern)&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;extension&lt;/span&gt; &lt;span class="hljs-title"&gt;SecretEntity&lt;/span&gt; &lt;/span&gt;{
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;toModel&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; -&amp;gt; &lt;span class="hljs-type"&gt;SecretModel&lt;/span&gt; {
        &lt;span class="hljs-type"&gt;SecretModel&lt;/span&gt;(title: &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.title ?? &lt;span class="hljs-string"&gt;""&lt;/span&gt;, value: &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.value ?? &lt;span class="hljs-string"&gt;""&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="assets-xcassets-uikit-edition"&gt;Assets.xcassets — UIKit Edition&lt;/h2&gt;
&lt;p&gt;The assets catalog works identically in UIKit and SwiftUI. In UIKit, you reference assets through &lt;code&gt;UIImage&lt;/code&gt; and &lt;code&gt;UIColor&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;// Load image from asset catalog
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-attr"&gt;logo&lt;/span&gt; = UIImage(named: &lt;span class="hljs-string"&gt;"Logo"&lt;/span&gt;)
imageView.&lt;span class="hljs-attr"&gt;image&lt;/span&gt; = logo

// SF Symbol (system icon, no asset needed)
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-attr"&gt;icon&lt;/span&gt; = UIImage(systemName: &lt;span class="hljs-string"&gt;"lock.shield"&lt;/span&gt;)
imageView.&lt;span class="hljs-attr"&gt;image&lt;/span&gt; = icon

// Tinted SF Symbol (iOS &lt;span class="hljs-number"&gt;15&lt;/span&gt;+)
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-attr"&gt;tinted&lt;/span&gt; = UIImage(systemName: &lt;span class="hljs-string"&gt;"lock.shield"&lt;/span&gt;)?.withTintColor(.systemBlue, renderingMode: .alwaysOriginal)

// Named colour from asset catalog
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; &lt;span class="hljs-attr"&gt;brandColor&lt;/span&gt; = UIColor(named: &lt;span class="hljs-string"&gt;"BrandBlue"&lt;/span&gt;)
view.&lt;span class="hljs-attr"&gt;backgroundColor&lt;/span&gt; = brandColor

// System semantic colours (automatically adapt to Dark Mode)
view.&lt;span class="hljs-attr"&gt;backgroundColor&lt;/span&gt; = .systemBackground          // white &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; Light, dark &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; Dark
label.&lt;span class="hljs-attr"&gt;textColor&lt;/span&gt; = .label                          // black &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; Light, white &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; Dark
textField.&lt;span class="hljs-attr"&gt;backgroundColor&lt;/span&gt; = .systemGray6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;Logo&lt;/code&gt; image in SecureRoom&lt;/strong&gt; is referenced in LockScreen.storyboard as an &lt;code&gt;UIImageView&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-xml"&gt;&amp;lt;imageView contentMode=&lt;span class="hljs-string"&gt;"scaleAspectFit"&lt;/span&gt; &lt;span class="hljs-built_in"&gt;image&lt;/span&gt;=&lt;span class="hljs-string"&gt;"Logo"&lt;/span&gt;
           translatesAutoresizingMaskIntoConstraints=&lt;span class="hljs-string"&gt;"NO"&lt;/span&gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At runtime, UIKit looks up &amp;quot;Logo&amp;quot; in the asset catalog and loads the correct &lt;code&gt;@1x&lt;/code&gt;, &lt;code&gt;@2x&lt;/code&gt;, or &lt;code&gt;@3x&lt;/code&gt; variant based on the device&amp;#39;s screen scale.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="uikit-ui-components-glossary"&gt;UIKit UI Components Glossary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;UIKit Class&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Text label&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UILabel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Non-interactive text. Set &lt;code&gt;.text&lt;/code&gt;, &lt;code&gt;.font&lt;/code&gt;, &lt;code&gt;.textColor&lt;/code&gt;, &lt;code&gt;.numberOfLines&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UITextField&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single-line editable text. Set &lt;code&gt;.placeholder&lt;/code&gt;, &lt;code&gt;.borderStyle&lt;/code&gt;, &lt;code&gt;.delegate&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-line text&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UITextView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scrollable multi-line text area. Supports rich text.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Button&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIButton&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tappable element. &lt;code&gt;buttonType: .system&lt;/code&gt; for text, &lt;code&gt;.custom&lt;/code&gt; for images.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIImageView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Displays &lt;code&gt;UIImage&lt;/code&gt;. Set &lt;code&gt;.contentMode&lt;/code&gt; for scaling behaviour.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Container&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The base class for all views. Can be used directly as a coloured box or container.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stack&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIStackView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Horizontal or vertical layout of arranged subviews.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scroll&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIScrollView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scrollable content area. Basis for &lt;code&gt;UITableView&lt;/code&gt; and &lt;code&gt;UICollectionView&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UITableView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Vertical scrolling list with reusable cells. The UIKit workhorse.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grid&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UICollectionView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Flexible grid/custom layout. More powerful than &lt;code&gt;UITableView&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Navigation bar&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UINavigationBar&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Top bar with title and back/action buttons. Managed by &lt;code&gt;UINavigationController&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tab bar&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UITabBar&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bottom tab selection. Managed by &lt;code&gt;UITabBarController&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alert&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIAlertController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modal alert or action sheet. Always presented with &lt;code&gt;present()&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Progress&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIActivityIndicatorView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spinning loader. &lt;code&gt;.startAnimating()&lt;/code&gt; / &lt;code&gt;.stopAnimating()&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switch&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UISwitch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle on/off. &lt;code&gt;.isOn&lt;/code&gt; property + &lt;code&gt;.valueChanged&lt;/code&gt; action.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slider&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UISlider&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continuous value selector. &lt;code&gt;.value&lt;/code&gt; + &lt;code&gt;.valueChanged&lt;/code&gt; action.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Segmented&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UISegmentedControl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multi-option tab strip. &lt;code&gt;.selectedSegmentIndex&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Picker&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIPickerView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spinning wheel selector. Requires &lt;code&gt;UIPickerViewDataSource&lt;/code&gt; + &lt;code&gt;UIPickerViewDelegate&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="uitextfield-uitextfielddelegate-deep-dive"&gt;UITextField &amp;amp; UITextFieldDelegate Deep Dive&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;UITextField&lt;/code&gt; is the primary single-line text input in UIKit. &lt;code&gt;LockScreenViewController&lt;/code&gt; uses a rich set of its features to implement the 4-digit PIN pad.&lt;/p&gt;
&lt;h3 id="setup-viewdidload-"&gt;Setup (viewDidLoad)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;// &lt;span class="hljs-keyword"&gt;Set&lt;/span&gt; the &lt;span class="hljs-keyword"&gt;delegate&lt;/span&gt; — &lt;span class="hljs-keyword"&gt;required&lt;/span&gt; &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; shouldChangeCharactersIn
textField1.delegate = &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;

// &lt;span class="hljs-keyword"&gt;Add&lt;/span&gt; a target-&lt;span class="hljs-keyword"&gt;action&lt;/span&gt; &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; programmatic &lt;span class="hljs-keyword"&gt;change&lt;/span&gt; notification
textField1.addTarget(&lt;span class="hljs-keyword"&gt;self&lt;/span&gt;, &lt;span class="hljs-keyword"&gt;action&lt;/span&gt;: #selector(textDidChange(_:)), &lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: .editingChanged)
// .editingChanged fires every &lt;span class="hljs-keyword"&gt;time&lt;/span&gt; the &lt;span class="hljs-built_in"&gt;text&lt;/span&gt; &lt;span class="hljs-keyword"&gt;value&lt;/span&gt; changes
// .editingDidBegin fires &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; the &lt;span class="hljs-keyword"&gt;field&lt;/span&gt; gains focus
// .editingDidEnd fires &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; focus &lt;span class="hljs-keyword"&gt;leaves&lt;/span&gt;

// Make a &lt;span class="hljs-keyword"&gt;field&lt;/span&gt; active (&lt;span class="hljs-keyword"&gt;show&lt;/span&gt; keyboard)
textField1.becomeFirstResponder()

// Dismiss keyboard &lt;span class="hljs-keyword"&gt;from&lt;/span&gt; a specific &lt;span class="hljs-keyword"&gt;field&lt;/span&gt;
textField1.resignFirstResponder()

// Dismiss keyboard &lt;span class="hljs-keyword"&gt;from&lt;/span&gt; &lt;span class="hljs-keyword"&gt;any&lt;/span&gt; &lt;span class="hljs-keyword"&gt;field&lt;/span&gt; &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; the &lt;span class="hljs-keyword"&gt;view&lt;/span&gt;
view.endEditing(&lt;span class="hljs-literal"&gt;true&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="uitextfielddelegate-protocol-methods"&gt;UITextFieldDelegate Protocol Methods&lt;/h3&gt;
&lt;p&gt;Delegates are a core UIKit pattern: the &lt;code&gt;UITextField&lt;/code&gt; calls methods on its delegate at specific points. The delegate (here &lt;code&gt;LockScreenViewController&lt;/code&gt;) implements the protocol methods it cares about.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;// Called BEFORE a character &lt;span class="hljs-keyword"&gt;change&lt;/span&gt; &lt;span class="hljs-keyword"&gt;is&lt;/span&gt; applied
// &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt; &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; &lt;span class="hljs-keyword"&gt;allow&lt;/span&gt; it, &lt;span class="hljs-literal"&gt;false&lt;/span&gt; &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; &lt;span class="hljs-keyword"&gt;block&lt;/span&gt; it
func textField(
    _ textField: UITextField,
    shouldChangeCharactersIn &lt;span class="hljs-keyword"&gt;range&lt;/span&gt;: NSRange,
    replacementString &lt;span class="hljs-keyword"&gt;string&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;String&lt;/span&gt;
) -&amp;gt; Bool {
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; string.isEmpty {
        // &lt;span class="hljs-keyword"&gt;string&lt;/span&gt; = &lt;span class="hljs-string"&gt;""&lt;/span&gt; means backspace
        // &lt;span class="hljs-keyword"&gt;Move&lt;/span&gt; focus &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; previous &lt;span class="hljs-keyword"&gt;field&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField2 { textField1.becomeFirstResponder() }
        &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField3 { textField2.becomeFirstResponder() }
        &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; textField == textField4 { textField3.becomeFirstResponder() }
        textField.text = &lt;span class="hljs-string"&gt;""&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-literal"&gt;false&lt;/span&gt;  // &lt;span class="hljs-keyword"&gt;block&lt;/span&gt; the &lt;span class="hljs-keyword"&gt;default&lt;/span&gt; deletion
    }
    // &lt;span class="hljs-keyword"&gt;Only&lt;/span&gt; &lt;span class="hljs-keyword"&gt;allow&lt;/span&gt; one &lt;span class="hljs-built_in"&gt;character&lt;/span&gt;: &lt;span class="hljs-keyword"&gt;reject&lt;/span&gt; &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; &lt;span class="hljs-keyword"&gt;field&lt;/span&gt; already has &lt;span class="hljs-keyword"&gt;content&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; textField.text?.isEmpty ?? &lt;span class="hljs-literal"&gt;true&lt;/span&gt;
}

// Called &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; the &lt;span class="hljs-keyword"&gt;Return&lt;/span&gt; &lt;span class="hljs-keyword"&gt;key&lt;/span&gt; &lt;span class="hljs-keyword"&gt;is&lt;/span&gt; tapped
func textFieldShouldReturn(_ textField: UITextField) -&amp;gt; Bool {
    textField.resignFirstResponder()
    &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;
}

// Called &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; &lt;span class="hljs-keyword"&gt;field&lt;/span&gt; &lt;span class="hljs-keyword"&gt;is&lt;/span&gt; about &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; become active
func textFieldShouldBeginEditing(_ textField: UITextField) -&amp;gt; Bool {
    &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;  // &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-literal"&gt;false&lt;/span&gt; &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; prevent editing
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="target-action-for-objc-methods"&gt;Target-Action for &lt;code&gt;@objc&lt;/code&gt; methods&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// The #selector mechanism — requires @objc for Objective-C runtime interop&lt;/span&gt;
&lt;span class="hljs-meta"&gt;@objc&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;textDidChange&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; textField: UITextField)&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; text = textField.text, !text.isEmpty &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; }
    &lt;span class="hljs-comment"&gt;// auto-advance to next field&lt;/span&gt;
}

&lt;span class="hljs-comment"&gt;// Selector syntax: #selector(textDidChange(_:))&lt;/span&gt;
&lt;span class="hljs-comment"&gt;// The (_:) means the method takes one unlabelled argument&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;#selector&lt;/code&gt; is required for all target-action callbacks because UIKit is built on Objective-C runtime. The &lt;code&gt;@objc&lt;/code&gt; attribute exposes the Swift method to Objective-C. Without it, the app crashes at runtime with an &amp;quot;unrecognised selector&amp;quot; exception.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="keyboard-management-in-uikit"&gt;Keyboard Management in UIKit&lt;/h2&gt;
&lt;p&gt;Unlike SwiftUI (which handles keyboard avoidance automatically), UIKit requires manual keyboard management.&lt;/p&gt;
&lt;h3 id="dismiss-keyboard-on-background-tap"&gt;Dismiss keyboard on background tap&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// In viewDidLoad:&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; tapGesture = &lt;span class="hljs-type"&gt;UITapGestureRecognizer&lt;/span&gt;(target: &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tapGesture)

&lt;span class="hljs-meta"&gt;@objc&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;dismissKeyboard&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
    view.endEditing(&lt;span class="hljs-literal"&gt;true&lt;/span&gt;)  &lt;span class="hljs-comment"&gt;// resigns first responder from any active text field&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="scroll-view-up-when-keyboard-appears-common-pattern-"&gt;Scroll view up when keyboard appears (common pattern)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;viewDidLoad&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-keyword"&gt;super&lt;/span&gt;.viewDidLoad()

    &lt;span class="hljs-comment"&gt;// Observe keyboard notifications&lt;/span&gt;
    &lt;span class="hljs-type"&gt;NotificationCenter&lt;/span&gt;.&lt;span class="hljs-keyword"&gt;default&lt;/span&gt;.addObserver(
        &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;,
        selector: #selector(keyboardWillShow(&lt;span class="hljs-number"&gt;_&lt;/span&gt;:)),
        name: &lt;span class="hljs-type"&gt;UIResponder&lt;/span&gt;.keyboardWillShowNotification,
        object: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;
    )
    &lt;span class="hljs-type"&gt;NotificationCenter&lt;/span&gt;.&lt;span class="hljs-keyword"&gt;default&lt;/span&gt;.addObserver(
        &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;,
        selector: #selector(keyboardWillHide),
        name: &lt;span class="hljs-type"&gt;UIResponder&lt;/span&gt;.keyboardWillHideNotification,
        object: &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;
    )
}

&lt;span class="hljs-meta"&gt;@objc&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;keyboardWillShow&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-number"&gt;_&lt;/span&gt; notification: Notification)&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; keyboardFrame = notification.userInfo?[&lt;span class="hljs-type"&gt;UIResponder&lt;/span&gt;.keyboardFrameEndUserInfoKey] &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;? &lt;span class="hljs-type"&gt;CGRect&lt;/span&gt; &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; }
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; keyboardHeight = keyboardFrame.height
    scrollView.contentInset.bottom = keyboardHeight
}

&lt;span class="hljs-meta"&gt;@objc&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;keyboardWillHide&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
    scrollView.contentInset.bottom = &lt;span class="hljs-number"&gt;0&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="uialertcontroller"&gt;UIAlertController&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;UIAlertController&lt;/code&gt; is UIKit&amp;#39;s system for modal alerts and action sheets. SecureRoom uses it to show error messages.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;func showAlert(&lt;span class="hljs-string"&gt;msg:&lt;/span&gt; String) {
    &lt;span class="hljs-comment"&gt;// preferredStyle: .alert → centred modal dialog&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;// preferredStyle: .actionSheet → slides up from bottom (use for destructive actions)&lt;/span&gt;
    let alert = UIAlertController(&lt;span class="hljs-string"&gt;title:&lt;/span&gt; &lt;span class="hljs-string"&gt;"Error"&lt;/span&gt;, &lt;span class="hljs-string"&gt;message:&lt;/span&gt; msg, &lt;span class="hljs-string"&gt;preferredStyle:&lt;/span&gt; .alert)

    let okAction = UIAlertAction(&lt;span class="hljs-string"&gt;title:&lt;/span&gt; &lt;span class="hljs-string"&gt;"OK"&lt;/span&gt;, &lt;span class="hljs-string"&gt;style:&lt;/span&gt; .&lt;span class="hljs-keyword"&gt;default&lt;/span&gt;, &lt;span class="hljs-string"&gt;handler:&lt;/span&gt; nil)
    &lt;span class="hljs-comment"&gt;// UIAlertAction styles:&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;// .default → normal blue text&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;// .destructive → red text (for delete/irreversible actions)&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;// .cancel → bold text, always last&lt;/span&gt;

    alert.addAction(okAction)

    &lt;span class="hljs-comment"&gt;// present() is how ALL modal VCs are shown in UIKit&lt;/span&gt;
    present(alert, &lt;span class="hljs-string"&gt;animated:&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;, &lt;span class="hljs-string"&gt;completion:&lt;/span&gt; nil)
}

&lt;span class="hljs-comment"&gt;// Action with handler (confirmDelete example)&lt;/span&gt;
let deleteAction = UIAlertAction(&lt;span class="hljs-string"&gt;title:&lt;/span&gt; &lt;span class="hljs-string"&gt;"Delete"&lt;/span&gt;, &lt;span class="hljs-string"&gt;style:&lt;/span&gt; .destructive) { _ &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
    self.deleteSecret()
}
let cancelAction = UIAlertAction(&lt;span class="hljs-string"&gt;title:&lt;/span&gt; &lt;span class="hljs-string"&gt;"Cancel"&lt;/span&gt;, &lt;span class="hljs-string"&gt;style:&lt;/span&gt; .cancel, &lt;span class="hljs-string"&gt;handler:&lt;/span&gt; nil)
alert.addAction(deleteAction)
alert.addAction(cancelAction)
present(alert, &lt;span class="hljs-string"&gt;animated:&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="data-flow-end-to-end"&gt;Data Flow: End-to-End&lt;/h2&gt;
&lt;p&gt;Here is the complete flow when a user enters their 4-digit passcode on launch:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-number"&gt;1.&lt;/span&gt; [Launch]       SceneDelegate.scene(willConnectTo:) fires
                  → Creates UIWindow
                  → Loads LockScreen.storyboard
                  → &lt;span class="hljs-keyword"&gt;Sets&lt;/span&gt; LockScreenViewController &lt;span class="hljs-comment"&gt;as window.rootViewController&lt;/span&gt;
                  → Calls &lt;span class="hljs-comment"&gt;window.makeKeyAndVisible()&lt;/span&gt;

2. [viewDidLoad]  LockScreenViewController.viewDidLoad() &lt;span class="hljs-comment"&gt;called&lt;/span&gt;
                  → &lt;span class="hljs-keyword"&gt;Sets&lt;/span&gt; &lt;span class="hljs-comment"&gt;delegate and addTarget on all 4 text fields&lt;/span&gt;
                  → Adds &lt;span class="hljs-comment"&gt;tap gesture recogniser to dismiss keyboard&lt;/span&gt;
                  → textField1.becomeFirstResponder() →&lt;span class="hljs-comment"&gt; keyboard appears&lt;/span&gt;
                  → Reads &lt;span class="hljs-comment"&gt;Keychain: if no passcode&lt;/span&gt; → &lt;span class="hljs-comment"&gt;"Welcome, create passcode"&lt;/span&gt;
                                    if &lt;span class="hljs-comment"&gt;passcode exists&lt;/span&gt; → &lt;span class="hljs-comment"&gt;"Enter passcode to unlock"&lt;/span&gt;

3. [User &lt;span class="hljs-comment"&gt;types]   User enters&lt;/span&gt; &lt;span class="hljs-comment"&gt;"4"&lt;/span&gt;&lt;span class="hljs-comment"&gt; in textField1&lt;/span&gt;
                  → UITextField &lt;span class="hljs-comment"&gt;calls textField(_:shouldChangeCharactersIn:replacementString:)&lt;/span&gt;
                  → textField1.text &lt;span class="hljs-comment"&gt;is empty&lt;/span&gt; →&lt;span class="hljs-comment"&gt; return true&lt;/span&gt; →&lt;span class="hljs-comment"&gt; character inserted&lt;/span&gt;
                  → .editingChanged &lt;span class="hljs-comment"&gt;fires&lt;/span&gt; →&lt;span class="hljs-comment"&gt; textDidChange(_:) called&lt;/span&gt;
                  → textField2.becomeFirstResponder() →&lt;span class="hljs-comment"&gt; keyboard focus moves to field 2&lt;/span&gt;

4. [User &lt;span class="hljs-comment"&gt;types]   Same for fields 2, 3, 4&lt;/span&gt;
                  → On &lt;span class="hljs-comment"&gt;field 4 entry: textDidChange calls verifyOtp() + dismissKeyboard()&lt;/span&gt;

5. [verifyOtp()]  Concatenates: otp &lt;span class="hljs-comment"&gt;=&lt;/span&gt; &lt;span class="hljs-comment"&gt;"\(tf1.text)\(tf2.text)\(tf3.text)\(tf4.text)"&lt;/span&gt;
                  → guard &lt;span class="hljs-comment"&gt;otp.count == 4 (always true at this point)&lt;/span&gt;
                  → KeychainManager.read(key: passcodeKey) → returns &lt;span class="hljs-comment"&gt;saved String?&lt;/span&gt;
                  → if &lt;span class="hljs-comment"&gt;savedPass == otp:&lt;/span&gt;
                       goToHome()
                    else:
                       showAlert(msg: &lt;span class="hljs-string"&gt;"Incorrect passcode"&lt;/span&gt;)
                       clearFields() →&lt;span class="hljs-comment"&gt; all fields .text =&lt;/span&gt; &lt;span class="hljs-comment"&gt;""&lt;/span&gt; →&lt;span class="hljs-comment"&gt; tf1.becomeFirstResponder()&lt;/span&gt;

6. [goToHome()]   Gets &lt;span class="hljs-comment"&gt;SceneDelegate via view.window?.windowScene?.delegate&lt;/span&gt;
                  → Loads &lt;span class="hljs-comment"&gt;HomeScreen.storyboard (UITabBarController)&lt;/span&gt;
                  → DispatchQueue.main.async:
                       sceneDelegate.window?.rootViewController &lt;span class="hljs-comment"&gt;= homeVc&lt;/span&gt;
                  → LockScreenViewController &lt;span class="hljs-comment"&gt;is deallocated&lt;/span&gt;
                  → UITabBarController &lt;span class="hljs-comment"&gt;with 3 tabs becomes visible&lt;/span&gt;

7. [Background]   User &lt;span class="hljs-comment"&gt;presses Home button&lt;/span&gt;
                  → SceneDelegate.sceneDidEnterBackground() &lt;span class="hljs-comment"&gt;fires&lt;/span&gt;
                  → (UIApplication.shared.delegate &lt;span class="hljs-comment"&gt;as? AppDelegate)?.saveContext()&lt;/span&gt;
                  → lockScreen() &lt;span class="hljs-comment"&gt;called:&lt;/span&gt;
                       Loads &lt;span class="hljs-comment"&gt;LockScreen.storyboard&lt;/span&gt;
                       DispatchQueue.main.async: window?.rootViewController &lt;span class="hljs-comment"&gt;= lockVc&lt;/span&gt;
                  → App &lt;span class="hljs-comment"&gt;is locked again&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="key-uikit-concepts-glossary"&gt;Key UIKit Concepts Glossary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Definition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIViewController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The base class for all screens. Manages a view hierarchy, responds to lifecycle events.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The base class for all visual elements. Every button, label, image is a &lt;code&gt;UIView&lt;/code&gt; subclass.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@IBOutlet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A reference from Swift code to a UI element in the Storyboard. Connected via Interface Builder. Must be &lt;code&gt;weak&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@IBAction&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A method in Swift that is called by a Storyboard UI event (button tap, etc.). Must be &lt;code&gt;@objc&lt;/code&gt; accessible.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;viewDidLoad()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called once after the view hierarchy is loaded from the Storyboard. First safe place to access &lt;code&gt;@IBOutlet&lt;/code&gt;s.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;viewWillAppear()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called every time the view is about to become visible. Use for data refresh.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;becomeFirstResponder()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Makes a view the &amp;quot;first responder&amp;quot; — for text fields this shows the keyboard.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resignFirstResponder()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gives up first responder status — hides keyboard for text fields.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;view.endEditing(true)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Forces all subviews to resign first responder. The easiest way to dismiss keyboard.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@objc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exposes a Swift method to the Objective-C runtime. Required for &lt;code&gt;#selector&lt;/code&gt;, &lt;code&gt;IBAction&lt;/code&gt;, &lt;code&gt;NSNotificationCenter&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#selector&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A compile-time checked reference to an Objective-C method. Used in &lt;code&gt;addTarget(_:action:for:)&lt;/code&gt;, &lt;code&gt;addObserver&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DispatchQueue.main.async&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Schedules work on the main thread (required for all UIKit updates).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIStoryboard(name:bundle:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Loads a compiled storyboard file. &lt;code&gt;bundle: nil&lt;/code&gt; = main app bundle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;instantiateInitialViewController()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates the Initial View Controller as configured in the storyboard.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;window.rootViewController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The topmost VC on screen. Replacing it swaps the entire UI instantly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;present(_:animated:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shows a modal view controller on top of the current one. Used for alerts, sheets.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dismiss(animated:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dismisses a modally presented view controller.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UIAlertController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;System modal alert or action sheet. Must be presented with &lt;code&gt;present()&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UITapGestureRecognizer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recognises a tap gesture on any view. Add with &lt;code&gt;addGestureRecognizer()&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delegate&lt;/code&gt; pattern&lt;/td&gt;
&lt;td&gt;Object A calls methods on object B (its delegate) at specific points. B implements a protocol. A has a &lt;code&gt;weak var delegate&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NSLayoutConstraint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A constraint between two view attributes defining their layout relationship.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;translatesAutoresizingMaskIntoConstraints = false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Must be set on code-created views before adding Auto Layout constraints.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;safeAreaLayoutGuide&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The area of the screen not obscured by the notch, Dynamic Island, or Home indicator.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lazy var&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Property computed only when first accessed. Useful for expensive setup like &lt;code&gt;NSPersistentContainer&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;as?&lt;/code&gt; / &lt;code&gt;as!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Conditional (&lt;code&gt;as?&lt;/code&gt;, safe) and forced (&lt;code&gt;as!&lt;/code&gt;, crashes if wrong) type downcasting.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;guard let&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Safely unwraps an optional; the &lt;code&gt;else&lt;/code&gt; block must exit scope. The idiomatic Swift safety check.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="uikit-vs-swiftui-side-by-side"&gt;UIKit vs SwiftUI — Side-by-Side&lt;/h2&gt;
&lt;p&gt;Since you&amp;#39;ve now seen both projects, here is a direct comparison of the same concepts:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;UIKit (SecureRoom)&lt;/th&gt;
&lt;th&gt;SwiftUI (FinSightAI)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Entry point&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@main class AppDelegate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@main struct FinSightAIApp: App&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Root window&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SceneDelegate&lt;/code&gt; sets &lt;code&gt;window.rootViewController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;WindowGroup { ... }&lt;/code&gt; in &lt;code&gt;App.body&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Define a screen&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;class MyViewController: UIViewController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;struct MyView: View&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UI layout&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Storyboard XML / &lt;code&gt;addSubview&lt;/code&gt; + Auto Layout&lt;/td&gt;
&lt;td&gt;&lt;code&gt;VStack&lt;/code&gt;, &lt;code&gt;HStack&lt;/code&gt;, &lt;code&gt;ZStack&lt;/code&gt; in &lt;code&gt;body&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Connect UI to code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@IBOutlet&lt;/code&gt; + &lt;code&gt;@IBAction&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$binding&lt;/code&gt;, &lt;code&gt;.onChange()&lt;/code&gt;, &lt;code&gt;Button(action:)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;var label: UILabel!&lt;/code&gt; + &lt;code&gt;label.text = &amp;quot;...&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@State var text = &amp;quot;&amp;quot;&lt;/code&gt; → auto-renders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Show keyboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;textField.becomeFirstResponder()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@FocusState&lt;/code&gt; + &lt;code&gt;.focused($field)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Navigate forward&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pushViewController&lt;/code&gt; / &lt;code&gt;window.rootViewController =&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NavigationStack&lt;/code&gt; + &lt;code&gt;route.push(.home)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pass data back&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;delegate&lt;/code&gt; protocol&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@Binding&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Show alert&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UIAlertController&lt;/code&gt; + &lt;code&gt;present()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.alert(isPresented:)&lt;/code&gt; modifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;App lifecycle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AppDelegate&lt;/code&gt; + &lt;code&gt;SceneDelegate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@UIApplicationDelegateAdaptor&lt;/code&gt; + scene phase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Async work&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DispatchQueue.main.async { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@MainActor&lt;/code&gt; + &lt;code&gt;Task { }&lt;/code&gt; + &lt;code&gt;await&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Secure storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Security&lt;/code&gt; framework directly&lt;/td&gt;
&lt;td&gt;Same — no SwiftUI equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Local database&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Core Data &lt;code&gt;NSPersistentContainer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same — no SwiftUI equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;SecureRoom demonstrates that UIKit, while more verbose than SwiftUI, gives you &lt;strong&gt;complete, explicit control&lt;/strong&gt; over every aspect of your app. Here is what each layer contributes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Files&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;App Lifecycle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AppDelegate&lt;/code&gt;, &lt;code&gt;SceneDelegate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;App-wide events, window management, lock-on-background, Core Data save&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Controllers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LockScreenViewController&lt;/code&gt;, &lt;code&gt;HomeViewController&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Receive user events via &lt;code&gt;@IBAction&lt;/code&gt;, update UI via &lt;code&gt;@IBOutlet&lt;/code&gt;, orchestrate navigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storyboards&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LockScreen.storyboard&lt;/code&gt;, &lt;code&gt;HomeScreen.storyboard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Visual UI layout, Auto Layout constraints, IBOutlet/IBAction connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Helpers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;KeychainManager&lt;/code&gt;, &lt;code&gt;Constants&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reusable utility logic. Keychain wraps the raw C &lt;code&gt;Security&lt;/code&gt; API. Constants prevent string literal duplication.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Models&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Secret.swift&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pure data structs. No UIKit. Fully portable and testable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Assets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Assets.xcassets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Images, colours, app icon. Accessed via &lt;code&gt;UIImage(named:)&lt;/code&gt; and &lt;code&gt;UIColor(named:)&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The most important UIKit principle is &lt;strong&gt;explicit control flow&lt;/strong&gt;: every state change, every UI update, every navigation transition is written by you. This is more code than SwiftUI, but it also means behaviour is entirely predictable — there is no magic re-rendering engine to reason about.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Based on the open-source &lt;a href="https://github.com/lkrjangid1/SecureRoom"&gt;SecureRoom&lt;/a&gt; project by Lokesh Jangid.&lt;/em&gt;&lt;/p&gt;
</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>&#128241; iOS Development with SwiftUI — A FinSightAI Deep Dive</title><link>https://flutdev.blogspot.com/2026/02/ios-development-from-first-principles.html</link><category>IOS</category><category>Swift</category><category>SwiftUI</category><author>noreply@blogger.com (Lokesh Jangid)</author><pubDate>Mon, 23 Feb 2026 20:42:00 -0800</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7439341812408440578.post-8661103661550647500</guid><description>&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;A complete breakdown of every layer of a real-world SwiftUI app.&lt;/strong&gt;
Based on the open-source &lt;a href="https://github.com/lkrjangid1/FinSightAI"&gt;FinSightAI&lt;/a&gt; project — an AI-powered financial education app for Indian stock market beginners, built with Swift, SwiftUI, and Google Gemini.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id="what-is-finsightai-"&gt;What is FinSightAI?&lt;/h2&gt;
&lt;p&gt;FinSightAI is a &lt;strong&gt;financial education chatbot&lt;/strong&gt; app. A user types in a stock name (e.g., "Reliance", "Infosys"), and the app sends that query to &lt;strong&gt;Google Gemini AI&lt;/strong&gt; with a crafted system prompt. The AI returns a beginner-friendly stock overview — fundamentals, technicals, key risks — and the app renders it inside a chat bubble with full markdown support.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tech stack:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Language:&lt;/strong&gt; Swift 5.9&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UI Framework:&lt;/strong&gt; SwiftUI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture:&lt;/strong&gt; MVVM (Model-View-ViewModel)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI:&lt;/strong&gt; Google Gemini API via raw &lt;code&gt;URLSession&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backend:&lt;/strong&gt; Firebase (for analytics/notifications)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigation:&lt;/strong&gt; &lt;code&gt;NavigationStack&lt;/code&gt; + &lt;code&gt;NavigationPath&lt;/code&gt; (modern programmatic navigation)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id="project-architecture-mvvm"&gt;Project Architecture — MVVM&lt;/h2&gt;
&lt;p&gt;MVVM is the dominant architecture for SwiftUI apps because SwiftUI's reactive property wrappers (&lt;code&gt;@Published&lt;/code&gt;, &lt;code&gt;@StateObject&lt;/code&gt;, &lt;code&gt;@ObservedObject&lt;/code&gt;) are designed specifically for it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                          &lt;span class="hljs-selector-tag"&gt;User&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Action&lt;/span&gt;                        │
│                      (types stock name)                     │
└────────────────────────────┬────────────────────────────────┘
                             │
                             ▼
┌────────────────────────────────────────────────────────────┐
│                    &lt;span class="hljs-selector-tag"&gt;VIEW&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;LAYER&lt;/span&gt; (SwiftUI)                    │
│   &lt;span class="hljs-selector-tag"&gt;HomeScreen&lt;/span&gt; → &lt;span class="hljs-selector-tag"&gt;shows&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;messages&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;sends&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;input&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;to&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;ViewModel&lt;/span&gt;    │
└────────────────────────────┬───────────────────────────────┘
                             │  &lt;span class="hljs-selector-tag"&gt;calls&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;vm&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.send&lt;/span&gt;()
                             ▼
┌────────────────────────────────────────────────────────────┐
│                  &lt;span class="hljs-selector-tag"&gt;VIEWMODEL&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;LAYER&lt;/span&gt;                           │
│   &lt;span class="hljs-selector-tag"&gt;ChatViewModel&lt;/span&gt; → &lt;span class="hljs-selector-tag"&gt;manages&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;state&lt;/span&gt; (&lt;span class="hljs-variable"&gt;@Published&lt;/span&gt; messages)      │
│   &lt;span class="hljs-selector-tag"&gt;calls&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;GeminiService&lt;/span&gt; (Networking sublayer)                │
└────────────────────────────┬───────────────────────────────┘
                             │  &lt;span class="hljs-selector-tag"&gt;async&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;API&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;call&lt;/span&gt;
                             ▼
┌────────────────────────────────────────────────────────────┐
│                  &lt;span class="hljs-selector-tag"&gt;NETWORKING&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;LAYER&lt;/span&gt;                          │
│   &lt;span class="hljs-selector-tag"&gt;GeminiService&lt;/span&gt; → &lt;span class="hljs-selector-tag"&gt;builds&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;URLRequest&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;decodes&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;response&lt;/span&gt;      │
└────────────────────────────┬───────────────────────────────┘
                             │  &lt;span class="hljs-selector-tag"&gt;Decodable&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;JSON&lt;/span&gt;
                             ▼
┌────────────────────────────────────────────────────────────┐
│                   &lt;span class="hljs-selector-tag"&gt;MODEL&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;LAYER&lt;/span&gt; (Data)                       │
│   &lt;span class="hljs-selector-tag"&gt;ChatMessage&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;GeminiResponse&lt;/span&gt; — &lt;span class="hljs-selector-tag"&gt;plain&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Swift&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;structs&lt;/span&gt;        │
└────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Why MVVM?&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What to display&lt;/td&gt;
&lt;td&gt;View&lt;/td&gt;
&lt;td&gt;Renders data, forwards user events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How to get data&lt;/td&gt;
&lt;td&gt;ViewModel&lt;/td&gt;
&lt;td&gt;Business logic, API calls, state management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What the data is&lt;/td&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;td&gt;Pure data structures, no UI imports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where to navigate&lt;/td&gt;
&lt;td&gt;Routes&lt;/td&gt;
&lt;td&gt;Centralised navigation state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App-wide config&lt;/td&gt;
&lt;td&gt;Resources&lt;/td&gt;
&lt;td&gt;Assets, plists, fonts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id="folder-structure"&gt;Folder Structure&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;FinSightAI/
└── FinSightAI/                         ← Xcode project root
    ├── FinSightAIApp&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;             ← @main entry point
    ├── Views/
    │   ├── elements/
    │   │   └── ChatBubble&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;        ← Reusable chat bubble component
    │   ├── HomeScreen&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;            ← Main chat UI
    │   ├── SplashScreen&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;          ← Launch screen
    │   ├── SettingsScreen&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;        ← Settings (placeholder)
    │   └── AboutScreen&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;           ← About page with gradient
    ├── ViewModels/
    │   ├── Networking/
    │   │   └── GeminiService&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;     ← URLSession API calls
    │   └── ViewModel/
    │       └── AIStudioViewModel&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt; ← ChatViewModel (state + logic)
    ├── Model/
    │   └── ChatMessageModel&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;      ← ChatMessage + GeminiResponse structs
    ├── Resources/
    │   ├── Assets&lt;span class="hljs-selector-class"&gt;.xcassets&lt;/span&gt;             ← Images, colors, app &lt;span class="hljs-attribute"&gt;icon&lt;/span&gt;
    │   └── GoogleService-Info&lt;span class="hljs-selector-class"&gt;.plist&lt;/span&gt;    ← Firebase configuration
    └── Routes/
        └── Route&lt;span class="hljs-selector-class"&gt;.swift&lt;/span&gt;                 ← NavigationPath + push/pop helpers
&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;h2 id="app-entry-point-finsightaiapp-swift-"&gt;App Entry Point — &lt;code&gt;FinSightAIApp.swift&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Every iOS app needs &lt;strong&gt;exactly one entry point&lt;/strong&gt; — the struct marked &lt;code&gt;@main&lt;/code&gt;. This is where the app boots, Firebase is configured, and the root navigation is set up.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;import&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;Firebase&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;import&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt;

&lt;span class="hljs-comment"&gt;// UIKit lifecycle hook — needed to configure Firebase before any view loads&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;class&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;AppDelegate&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;NSObject&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;UIApplicationDelegate&lt;/span&gt; {
    &lt;span class="hljs-selector-tag"&gt;func&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;application&lt;/span&gt;(
        _ &lt;span class="hljs-attribute"&gt;application&lt;/span&gt;: UIApplication,
        didFinishLaunchingWithOptions &lt;span class="hljs-attribute"&gt;launchOptions&lt;/span&gt;: [UIApplication
            .&lt;span class="hljs-attribute"&gt;LaunchOptionsKey&lt;/span&gt;: Any]? = nil
    ) &lt;span class="hljs-selector-tag"&gt;-&lt;/span&gt;&amp;gt; &lt;span class="hljs-selector-tag"&gt;Bool&lt;/span&gt; {
        &lt;span class="hljs-selector-tag"&gt;FirebaseApp&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.configure&lt;/span&gt;()   &lt;span class="hljs-comment"&gt;// initialise Firebase SDKs&lt;/span&gt;
        &lt;span class="hljs-selector-tag"&gt;return&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;true&lt;/span&gt;
    }
}

@&lt;span class="hljs-selector-tag"&gt;main&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;struct&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;FinSightAIApp&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;App&lt;/span&gt; {
    &lt;span class="hljs-comment"&gt;// Bridge UIKit AppDelegate into SwiftUI lifecycle&lt;/span&gt;
    &lt;span class="hljs-variable"&gt;@UIApplicationDelegateAdaptor&lt;/span&gt;(AppDelegate.self) var delegate

    &lt;span class="hljs-comment"&gt;// Route is created once here and injected via environmentObject&lt;/span&gt;
    &lt;span class="hljs-variable"&gt;@StateObject&lt;/span&gt; private var route = Route()

    &lt;span class="hljs-comment"&gt;// Controls whether the splash screen shows&lt;/span&gt;
    &lt;span class="hljs-variable"&gt;@State&lt;/span&gt; private var showSplash = true

    var &lt;span class="hljs-attribute"&gt;body&lt;/span&gt;: some Scene {
        &lt;span class="hljs-selector-tag"&gt;WindowGroup&lt;/span&gt; {
            &lt;span class="hljs-selector-tag"&gt;if&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;showSplash&lt;/span&gt; {
                &lt;span class="hljs-selector-tag"&gt;SplashScreen&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;showSplash&lt;/span&gt;: $showSplash)
            } &lt;span class="hljs-selector-tag"&gt;else&lt;/span&gt; {
                &lt;span class="hljs-comment"&gt;// NavigationStack is the modern (iOS 16+) navigation container&lt;/span&gt;
                &lt;span class="hljs-selector-tag"&gt;NavigationStack&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;path&lt;/span&gt;: $route.navPath) {
                    &lt;span class="hljs-selector-tag"&gt;HomeScreen&lt;/span&gt;()
                        &lt;span class="hljs-selector-class"&gt;.navigationDestination&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;for&lt;/span&gt;: Route.RouteName.self) { &lt;span class="hljs-selector-tag"&gt;dest&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;in&lt;/span&gt;
                            &lt;span class="hljs-selector-tag"&gt;switch&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;dest&lt;/span&gt; {
                            &lt;span class="hljs-selector-tag"&gt;case&lt;/span&gt; &lt;span class="hljs-selector-class"&gt;.home&lt;/span&gt;:     &lt;span class="hljs-selector-tag"&gt;HomeScreen&lt;/span&gt;()
                            &lt;span class="hljs-selector-tag"&gt;case&lt;/span&gt; &lt;span class="hljs-selector-class"&gt;.settings&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;SettingsScreen&lt;/span&gt;()
                            &lt;span class="hljs-selector-tag"&gt;case&lt;/span&gt; &lt;span class="hljs-selector-class"&gt;.about&lt;/span&gt;:    &lt;span class="hljs-selector-tag"&gt;AboutScreen&lt;/span&gt;()
                            }
                        }
                }
                &lt;span class="hljs-selector-class"&gt;.environmentObject&lt;/span&gt;(route)  &lt;span class="hljs-comment"&gt;// makes `route` available to all child views&lt;/span&gt;
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="key-concepts-used-here"&gt;Key concepts used here&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@main&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Marks this struct as the application entry point — Xcode replaces the old &lt;code&gt;main.swift&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;App&lt;/code&gt; protocol&lt;/td&gt;
&lt;td&gt;SwiftUI's equivalent of &lt;code&gt;UIApplicationDelegate&lt;/code&gt;; defines the root &lt;code&gt;Scene&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WindowGroup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The content window — handles multitasking, multiple windows on iPad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@StateObject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates an &lt;code&gt;ObservableObject&lt;/code&gt; instance that lives for the lifetime of the owning view; use for top-level objects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@State&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Owned local reactive value; changes trigger a re-render of &lt;code&gt;body&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@UIApplicationDelegateAdaptor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bridges old UIKit lifecycle events (needed for Firebase, Push Notifications) into a SwiftUI app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.environmentObject()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Injects an &lt;code&gt;ObservableObject&lt;/code&gt; into the SwiftUI environment so any descendant view can access it with &lt;code&gt;@EnvironmentObject&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NavigationStack(path:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Programmatic navigation using a &lt;code&gt;NavigationPath&lt;/code&gt; stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.navigationDestination(for:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Declares which view to show for each route type&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id="views-layer"&gt;Views Layer&lt;/h2&gt;
&lt;h3 id="the-view-protocol"&gt;The View Protocol&lt;/h3&gt;
&lt;p&gt;In SwiftUI &lt;strong&gt;every UI element is a &lt;code&gt;View&lt;/code&gt;&lt;/strong&gt;. A &lt;code&gt;View&lt;/code&gt; is a &lt;code&gt;struct&lt;/code&gt; that conforms to the &lt;code&gt;View&lt;/code&gt; protocol, which requires exactly one thing: a &lt;code&gt;body&lt;/code&gt; property that returns &lt;code&gt;some View&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;MyView&lt;/span&gt;: View &lt;/span&gt;{
    var body: some View {
        &lt;span class="hljs-built_in"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Hello, World!"&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;some View&lt;/code&gt; is an &lt;strong&gt;opaque return type&lt;/strong&gt; — it tells Swift "this returns some specific View type, but I don't need to spell out which one." The compiler figures it out.&lt;/p&gt;
&lt;p&gt;SwiftUI views are &lt;strong&gt;value types&lt;/strong&gt; (structs). This is intentional — they are cheap to create, re-create, and compare, making the diffing system fast.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="layout-containers-vstack-hstack-zstack"&gt;Layout Containers: VStack, HStack, ZStack&lt;/h3&gt;
&lt;p&gt;These three containers replace UIKit's Auto Layout system entirely.&lt;/p&gt;
&lt;h4 id="-vstack-vertical-stack"&gt;&lt;code&gt;VStack&lt;/code&gt; — Vertical Stack&lt;/h4&gt;
&lt;p&gt;Arranges children &lt;strong&gt;top-to-bottom&lt;/strong&gt;. Every screen you build will almost certainly have a root &lt;code&gt;VStack&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;VStack&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;alignment&lt;/span&gt;: .leading, &lt;span class="hljs-attribute"&gt;spacing&lt;/span&gt;: &lt;span class="hljs-number"&gt;16&lt;/span&gt;) {
    &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Title"&lt;/span&gt;)
        &lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(.title)
    &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Subtitle"&lt;/span&gt;)
        &lt;span class="hljs-selector-class"&gt;.foregroundColor&lt;/span&gt;(.secondary)
    &lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Tap me"&lt;/span&gt;) { }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alignment&lt;/code&gt;: &lt;code&gt;.leading&lt;/code&gt;, &lt;code&gt;.center&lt;/code&gt;, &lt;code&gt;.trailing&lt;/code&gt; — how items align on the cross axis&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spacing&lt;/code&gt;: fixed gap between each child&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="-hstack-horizontal-stack"&gt;&lt;code&gt;HStack&lt;/code&gt; — Horizontal Stack&lt;/h4&gt;
&lt;p&gt;Arranges children &lt;strong&gt;left-to-right&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;HStack&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;alignment&lt;/span&gt;: .top, &lt;span class="hljs-attribute"&gt;spacing&lt;/span&gt;: &lt;span class="hljs-number"&gt;12&lt;/span&gt;) {
    &lt;span class="hljs-selector-tag"&gt;Image&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;systemName&lt;/span&gt;: &lt;span class="hljs-string"&gt;"person.circle"&lt;/span&gt;)
    &lt;span class="hljs-selector-tag"&gt;VStack&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;alignment&lt;/span&gt;: .leading) {
        &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Lokesh Jangid"&lt;/span&gt;)
            &lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(.headline)
        &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"iOS Developer"&lt;/span&gt;)
            &lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(.caption)
    }
    &lt;span class="hljs-selector-tag"&gt;Spacer&lt;/span&gt;()   &lt;span class="hljs-comment"&gt;// pushes everything to the left&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Spacer()&lt;/code&gt; is a flexible space that expands to fill available room — used to push items to either end of a stack.&lt;/p&gt;
&lt;h4 id="-zstack-depth-stack"&gt;&lt;code&gt;ZStack&lt;/code&gt; — Depth Stack&lt;/h4&gt;
&lt;p&gt;Layers children on top of each other (Z axis). Used for backgrounds, overlays, badges.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;ZStack&lt;/span&gt; {
    &lt;span class="hljs-selector-tag"&gt;LinearGradient&lt;/span&gt;(
        &lt;span class="hljs-attribute"&gt;colors&lt;/span&gt;: [.blue, .purple],
        &lt;span class="hljs-attribute"&gt;startPoint&lt;/span&gt;: .topLeading,
        &lt;span class="hljs-attribute"&gt;endPoint&lt;/span&gt;: .bottomTrailing
    )
    &lt;span class="hljs-selector-class"&gt;.ignoresSafeArea&lt;/span&gt;()                      &lt;span class="hljs-comment"&gt;// gradient covers entire screen&lt;/span&gt;

    &lt;span class="hljs-selector-tag"&gt;VStack&lt;/span&gt; {
        &lt;span class="hljs-selector-tag"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"FinSight AI"&lt;/span&gt;)
            &lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(.largeTitle)
            &lt;span class="hljs-selector-class"&gt;.foregroundColor&lt;/span&gt;(.white)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="other-important-containers-used-in-finsightai"&gt;Other important containers used in FinSightAI&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Container&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ScrollView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scrollable content in any direction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LazyVStack&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Like &lt;code&gt;VStack&lt;/code&gt; but only renders items when they're visible — critical for long chat lists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ScrollViewReader&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Programmatically scroll to a specific view by ID (used to scroll to the latest message)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ForEach&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Renders a collection of views from an array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Group&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Groups views without adding layout (useful for conditional logic)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h3 id="splashscreen-swift"&gt;SplashScreen.swift&lt;/h3&gt;
&lt;p&gt;The splash screen shows for 1 second on launch, then removes itself using &lt;code&gt;@Binding&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; SwiftUI

struct SplashScreen: View {
    &lt;span class="hljs-comment"&gt;// @Binding creates a two-way connection to a value owned by the parent&lt;/span&gt;
    &lt;span class="hljs-meta"&gt;@Binding&lt;/span&gt; var showSplash: Bool

    var body: some View {
        VStack(spacing: 20) {
            Image(systemName: &lt;span class="hljs-string"&gt;"wand.and.stars.inverse"&lt;/span&gt;)
                .font(.system(size: 60))
            Text(&lt;span class="hljs-string"&gt;"FinSight AI"&lt;/span&gt;)
                .font(.largeTitle)
        }
        .task {
            &lt;span class="hljs-comment"&gt;// .task attaches an async task to the view's lifecycle&lt;/span&gt;
            &lt;span class="hljs-comment"&gt;// It runs when the view appears and cancels if the view disappears&lt;/span&gt;
            &lt;span class="hljs-keyword"&gt;try&lt;/span&gt;? await Task.sleep(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: .seconds(1))
            showSplash = &lt;span class="hljs-keyword"&gt;false&lt;/span&gt;   // writes back through the binding — parent's @State updates
        }
    }
}

#Preview {
    SplashScreen(showSplash: .constant(&lt;span class="hljs-keyword"&gt;true&lt;/span&gt;))
    // .constant() creates a Binding that never changes — good &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; previews
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="key-concepts"&gt;Key concepts&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Binding&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A reference to a value owned somewhere else. Reading it reads the parent's value; writing it writes the parent's value. No data is duplicated.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.task { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SwiftUI modifier that runs an &lt;code&gt;async&lt;/code&gt; closure tied to the view's appearance. Automatically cancelled when the view disappears. Modern replacement for &lt;code&gt;onAppear&lt;/code&gt; + &lt;code&gt;Task { }&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Task.sleep(for:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Suspends the current async task without blocking any thread. Requires &lt;code&gt;try?&lt;/code&gt; because it can be cancelled.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#Preview&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Xcode 15+ macro that registers a preview. Shown in the canvas without needing to run the simulator.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h3 id="homescreen-swift"&gt;HomeScreen.swift&lt;/h3&gt;
&lt;p&gt;The main screen of the app. This is the most instructive file — it shows how Views and ViewModels connect.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; SwiftUI

struct HomeScreen: View {
    // @&lt;span class="hljs-attribute"&gt;StateObject creates the ViewModel and owns it
    // Use @StateObject when THIS view creates the object
    @StateObject private var chatModel = ChatViewModel()

    var body&lt;/span&gt;: some View {
        VStack(spacing: 0) {

            // ── Message list ─────────────────────────────
            ScrollViewReader { proxy in
                // proxy lets us programmatically scroll to a view by ID
                ScrollView {
                    LazyVStack(spacing: 10) {
                        ForEach(chatModel&lt;span class="hljs-variable"&gt;.messages&lt;/span&gt;) { message in
                            ChatBubble(message: message)
                                &lt;span class="hljs-variable"&gt;.id&lt;/span&gt;(message&lt;span class="hljs-variable"&gt;.id&lt;/span&gt;)   // gives each bubble an anchor ID
                        }
                    }
                    &lt;span class="hljs-variable"&gt;.padding&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.vertical&lt;/span&gt;)
                }
                // Fires when messages&lt;span class="hljs-variable"&gt;.count&lt;/span&gt; changes → scroll to the new message
                &lt;span class="hljs-variable"&gt;.onChange&lt;/span&gt;(of: chatModel&lt;span class="hljs-variable"&gt;.messages&lt;/span&gt;&lt;span class="hljs-variable"&gt;.count&lt;/span&gt;) { oldValue, newValue in
                    if let lastMessage = chatModel&lt;span class="hljs-variable"&gt;.messages&lt;/span&gt;&lt;span class="hljs-variable"&gt;.last&lt;/span&gt; {
                        withAnimation {
                            proxy&lt;span class="hljs-variable"&gt;.scrollTo&lt;/span&gt;(lastMessage&lt;span class="hljs-variable"&gt;.id&lt;/span&gt;, anchor: &lt;span class="hljs-variable"&gt;.bottom&lt;/span&gt;)
                        }
                    }
                }
            }

            // ── Input bar ────────────────────────────────
            HStack(spacing: 12) {
                // Multi-line expandable text field (axis: &lt;span class="hljs-variable"&gt;.vertical&lt;/span&gt;)
                TextField(
                    "Input a stock name to get information",
                    text: $chatModel&lt;span class="hljs-variable"&gt;.inputText&lt;/span&gt;,   // two-way binding to ViewModel's @Published var
                    axis: &lt;span class="hljs-variable"&gt;.vertical&lt;/span&gt;
                )
                &lt;span class="hljs-variable"&gt;.onSubmit&lt;/span&gt; { chatModel&lt;span class="hljs-variable"&gt;.send&lt;/span&gt;() }    // fires when user taps Return
                &lt;span class="hljs-variable"&gt;.textFieldStyle&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.plain&lt;/span&gt;)
                &lt;span class="hljs-variable"&gt;.padding&lt;/span&gt;(10)
                &lt;span class="hljs-variable"&gt;.background&lt;/span&gt;(Color(&lt;span class="hljs-variable"&gt;.systemGray&lt;/span&gt;6))
                &lt;span class="hljs-variable"&gt;.clipShape&lt;/span&gt;(RoundedRectangle(cornerRadius: 20))
                &lt;span class="hljs-variable"&gt;.lineLimit&lt;/span&gt;(1...5)

                // Show spinner while AI is thinking, else show send button
                if chatModel&lt;span class="hljs-variable"&gt;.isLoading&lt;/span&gt; {
                    ProgressView()
                } else {
                    Button(action: chatModel&lt;span class="hljs-variable"&gt;.send&lt;/span&gt;) {
                        Image(systemName: "arrow&lt;span class="hljs-variable"&gt;.up&lt;/span&gt;&lt;span class="hljs-variable"&gt;.circle&lt;/span&gt;&lt;span class="hljs-variable"&gt;.fill&lt;/span&gt;")
                            &lt;span class="hljs-variable"&gt;.font&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.system&lt;/span&gt;(size: 32))
                            &lt;span class="hljs-variable"&gt;.foregroundStyle&lt;/span&gt;(
                                chatModel&lt;span class="hljs-variable"&gt;.inputText&lt;/span&gt;&lt;span class="hljs-variable"&gt;.isEmpty&lt;/span&gt; ? &lt;span class="hljs-variable"&gt;.gray&lt;/span&gt; : &lt;span class="hljs-variable"&gt;.blue&lt;/span&gt;
                            )
                    }
                    &lt;span class="hljs-variable"&gt;.disabled&lt;/span&gt;(chatModel&lt;span class="hljs-variable"&gt;.inputText&lt;/span&gt;&lt;span class="hljs-variable"&gt;.isEmpty&lt;/span&gt;)
                }
            }
            &lt;span class="hljs-variable"&gt;.padding&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.horizontal&lt;/span&gt;)
            &lt;span class="hljs-variable"&gt;.padding&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.vertical&lt;/span&gt;, 8)
            &lt;span class="hljs-variable"&gt;.background&lt;/span&gt;(Color(&lt;span class="hljs-variable"&gt;.systemBackground&lt;/span&gt;))
        }
        &lt;span class="hljs-variable"&gt;.navigationTitle&lt;/span&gt;("FinSight AI")
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="key-concepts"&gt;Key concepts&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@StateObject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates and owns an &lt;code&gt;ObservableObject&lt;/code&gt;. The view that creates it should use &lt;code&gt;@StateObject&lt;/code&gt;; views that receive it should use &lt;code&gt;@ObservedObject&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$chatModel.inputText&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;$&lt;/code&gt; prefix turns a &lt;code&gt;@Published&lt;/code&gt; property into a &lt;code&gt;Binding&amp;lt;String&amp;gt;&lt;/code&gt;, enabling two-way sync between the &lt;code&gt;TextField&lt;/code&gt; and the ViewModel's value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ForEach&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Iterates over a collection that conforms to &lt;code&gt;Identifiable&lt;/code&gt; and renders a view for each item.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ScrollViewReader&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gives access to a &lt;code&gt;ScrollViewProxy&lt;/code&gt; that can call &lt;code&gt;.scrollTo(id:)&lt;/code&gt; to jump to any view with a matching &lt;code&gt;.id()&lt;/code&gt; modifier.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.onChange(of:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A view modifier that fires a closure when a value changes. Used here to auto-scroll when messages are added.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;withAnimation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wraps a state change in an implicit animation transaction so the scroll movement is smooth.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LazyVStack&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Renders items lazily — only those currently visible on screen are in memory. Essential for chat lists.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Button(action:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates a tappable button. The closure runs on tap. &lt;code&gt;.disabled()&lt;/code&gt; greyes it out and prevents taps.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ProgressView()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Renders the system spinner. No configuration needed for the default indeterminate spinner.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TextField(_:text:axis:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multi-line text input with the &lt;code&gt;axis: .vertical&lt;/code&gt; parameter (iOS 16+). Grows vertically up to &lt;code&gt;lineLimit&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h3 id="chatbubble-swift-reusable-element-"&gt;ChatBubble.swift (Reusable Element)&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;elements/&lt;/code&gt; subfolder is a great pattern: it holds &lt;strong&gt;small, reusable view components&lt;/strong&gt; that are not full screens. &lt;code&gt;ChatBubble&lt;/code&gt; is the single UI element that renders both user messages and AI responses.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; SwiftUI

struct ChatBubble: View {
    &lt;span class="hljs-attribute"&gt;let message&lt;/span&gt;: ChatMessage   // passed in from the parent — no @State needed for display-only data

    var body: some View {
        HStack(alignment: &lt;span class="hljs-variable"&gt;.top&lt;/span&gt;, spacing: 0) {
            // Push user bubbles to the right with a leading Spacer
            if message&lt;span class="hljs-variable"&gt;.isMe&lt;/span&gt; { Spacer(minLength: 50) }

            VStack(alignment: message&lt;span class="hljs-variable"&gt;.isMe&lt;/span&gt; ? &lt;span class="hljs-variable"&gt;.trailing&lt;/span&gt; : &lt;span class="hljs-variable"&gt;.leading&lt;/span&gt;, spacing: 0) {
                if message&lt;span class="hljs-variable"&gt;.isMe&lt;/span&gt; {
                    Text(message&lt;span class="hljs-variable"&gt;.text&lt;/span&gt;)
                        &lt;span class="hljs-variable"&gt;.padding&lt;/span&gt;(12)
                        &lt;span class="hljs-variable"&gt;.background&lt;/span&gt;(Color&lt;span class="hljs-variable"&gt;.blue&lt;/span&gt;)
                        &lt;span class="hljs-variable"&gt;.foregroundColor&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.white&lt;/span&gt;)
                        &lt;span class="hljs-variable"&gt;.clipShape&lt;/span&gt;(RoundedRectangle(cornerRadius: 16))
                } else {
                    // AI response — render as markdown
                    MarkdownText(message&lt;span class="hljs-variable"&gt;.text&lt;/span&gt;)
                        &lt;span class="hljs-variable"&gt;.padding&lt;/span&gt;(12)
                        &lt;span class="hljs-variable"&gt;.background&lt;/span&gt;(Color&lt;span class="hljs-variable"&gt;.gray&lt;/span&gt;&lt;span class="hljs-variable"&gt;.opacity&lt;/span&gt;(0.15))
                        &lt;span class="hljs-variable"&gt;.clipShape&lt;/span&gt;(RoundedRectangle(cornerRadius: 16))
                }
            }

            // Push AI bubbles to the left with a trailing Spacer
            if !message&lt;span class="hljs-variable"&gt;.isMe&lt;/span&gt; { Spacer(minLength: 50) }
        }
        &lt;span class="hljs-variable"&gt;.padding&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.horizontal&lt;/span&gt;)
    }
}

// Sub-view that renders Markdown using AttributedString
struct MarkdownText: View {
    let text: String

    var body: some View {
        VStack(alignment: &lt;span class="hljs-variable"&gt;.leading&lt;/span&gt;, spacing: 8) {
            if let attributed = try? AttributedString(
                markdown: text,
                options: AttributedString&lt;span class="hljs-variable"&gt;.MarkdownParsingOptions&lt;/span&gt;(
                    interpretedSyntax: &lt;span class="hljs-variable"&gt;.inlineOnlyPreservingWhitespace&lt;/span&gt;
                )
            ) {
                Text(attributed)
                    &lt;span class="hljs-variable"&gt;.textSelection&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.enabled&lt;/span&gt;)   // user can long-press to copy
                    &lt;span class="hljs-variable"&gt;.font&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.body&lt;/span&gt;)
                    &lt;span class="hljs-variable"&gt;.foregroundColor&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.primary&lt;/span&gt;)
            } else {
                Text(text)    // fallback if markdown parsing fails
                    &lt;span class="hljs-variable"&gt;.textSelection&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.enabled&lt;/span&gt;)
                    &lt;span class="hljs-variable"&gt;.font&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.body&lt;/span&gt;)
                    &lt;span class="hljs-variable"&gt;.foregroundColor&lt;/span&gt;(&lt;span class="hljs-variable"&gt;.primary&lt;/span&gt;)
            }
        }
        &lt;span class="hljs-variable"&gt;.frame&lt;/span&gt;(maxWidth: &lt;span class="hljs-variable"&gt;.infinity&lt;/span&gt;, alignment: &lt;span class="hljs-variable"&gt;.leading&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="key-concepts"&gt;Key concepts&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Stored property (&lt;code&gt;let message&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Views that only display data (no user interaction changes it) just take a &lt;code&gt;let&lt;/code&gt; — no state wrapper needed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conditional views (&lt;code&gt;if message.isMe&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;SwiftUI builds different view trees depending on runtime conditions. Each branch is fully independent.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.clipShape(RoundedRectangle(cornerRadius:))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clips the view to a rounded rectangle shape — the standard way to make rounded bubbles.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Spacer(minLength:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Flexible space. &lt;code&gt;minLength&lt;/code&gt; ensures it never collapses below that size, keeping the bubble from stretching full-width.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AttributedString(markdown:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Parses a markdown string into a rich attributed string with bold, italic, lists, etc. Introduced in iOS 15.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.textSelection(.enabled)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lets the user long-press to select and copy text — important for AI responses.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Color.gray.opacity(0.15)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Semi-transparent colour — adapts automatically between Light and Dark Mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h3 id="settingsscreen-swift-aboutscreen-swift"&gt;SettingsScreen.swift &amp;amp; AboutScreen.swift&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;SettingsScreen&lt;/strong&gt; is a placeholder — it demonstrates the minimum valid SwiftUI view:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;SettingsScreen&lt;/span&gt;: View &lt;/span&gt;{
    var body: some View {
        &lt;span class="hljs-built_in"&gt;Text&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Settings"&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every production app starts this way. The view can always be expanded later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AboutScreen&lt;/strong&gt; uses a &lt;code&gt;ZStack&lt;/code&gt; to layer a &lt;code&gt;LinearGradient&lt;/code&gt; background behind content:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;struct AboutScreen: View {
    &lt;span class="hljs-selector-tag"&gt;var&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt;: some View {
        ZStack {
            LinearGradient(
                colors: [&lt;span class="hljs-selector-class"&gt;.blue&lt;/span&gt;, .purple],
                startPoint: &lt;span class="hljs-selector-class"&gt;.topLeading&lt;/span&gt;,
                endPoint: &lt;span class="hljs-selector-class"&gt;.bottomTrailing&lt;/span&gt;
            )
            &lt;span class="hljs-comment"&gt;// ... content on top&lt;/span&gt;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;LinearGradient&lt;/code&gt; takes an array of &lt;code&gt;Color&lt;/code&gt; values and interpolates between them from &lt;code&gt;startPoint&lt;/code&gt; to &lt;code&gt;endPoint&lt;/code&gt;. Both points are &lt;code&gt;UnitPoint&lt;/code&gt; values: &lt;code&gt;.topLeading&lt;/code&gt;, &lt;code&gt;.bottomTrailing&lt;/code&gt;, &lt;code&gt;.center&lt;/code&gt;, etc.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="viewmodels-layer"&gt;ViewModels Layer&lt;/h2&gt;
&lt;h3 id="what-is-observableobject-"&gt;What is ObservableObject?&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ObservableObject&lt;/code&gt; is a protocol from the &lt;strong&gt;Combine&lt;/strong&gt; framework. When a class conforms to it, its &lt;code&gt;@Published&lt;/code&gt; properties become publishers. Any SwiftUI view observing this object (via &lt;code&gt;@StateObject&lt;/code&gt; or &lt;code&gt;@ObservedObject&lt;/code&gt;) automatically re-renders when any &lt;code&gt;@Published&lt;/code&gt; property changes.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-selector-tag"&gt;ViewModel&lt;/span&gt; (&lt;span class="hljs-variable"&gt;@Published&lt;/span&gt; var messages changes)
         │
         └──► &lt;span class="hljs-selector-tag"&gt;SwiftUI&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;diffs&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;the&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;View&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;tree&lt;/span&gt;
                   │
                   └──► &lt;span class="hljs-selector-tag"&gt;Re-renders&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;only&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;the&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;affected&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;parts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is the &lt;strong&gt;reactive binding&lt;/strong&gt; at the core of MVVM in SwiftUI.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3 id="aistudioviewmodel-swift-chatviewmodel"&gt;AIStudioViewModel.swift — ChatViewModel&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; Foundation
&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; SwiftUI
&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; Combine

&lt;span class="hljs-comment"&gt;// @MainActor guarantees all @Published mutations happen on the main thread&lt;/span&gt;
&lt;span class="hljs-comment"&gt;// (required for UI updates)&lt;/span&gt;
@&lt;span class="hljs-type"&gt;MainActor&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;final&lt;/span&gt; &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;ChatViewModel&lt;/span&gt;: &lt;span class="hljs-title"&gt;ObservableObject&lt;/span&gt; &lt;/span&gt;{

    @&lt;span class="hljs-type"&gt;Published&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; messages: [&lt;span class="hljs-type"&gt;ChatMessage&lt;/span&gt;] = []   &lt;span class="hljs-comment"&gt;// the message list — drives the UI&lt;/span&gt;
    @&lt;span class="hljs-type"&gt;Published&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; isLoading = &lt;span class="hljs-literal"&gt;false&lt;/span&gt;              &lt;span class="hljs-comment"&gt;// shows/hides the spinner&lt;/span&gt;
    @&lt;span class="hljs-type"&gt;Published&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; inputText = &lt;span class="hljs-string"&gt;""&lt;/span&gt;                 &lt;span class="hljs-comment"&gt;// bound to the TextField&lt;/span&gt;

    &lt;span class="hljs-comment"&gt;// The networking layer — dependency injected (easy to swap for testing)&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; service = &lt;span class="hljs-type"&gt;GeminiService&lt;/span&gt;()

    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;send&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; userText = inputText.trimmingCharacters(&lt;span class="hljs-keyword"&gt;in&lt;/span&gt;: .whitespaces)
        &lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; !userText.isEmpty &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; { &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; }   &lt;span class="hljs-comment"&gt;// guard: early exit pattern&lt;/span&gt;

        inputText = &lt;span class="hljs-string"&gt;""&lt;/span&gt;                             &lt;span class="hljs-comment"&gt;// clear the input field immediately&lt;/span&gt;
        messages.append(&lt;span class="hljs-type"&gt;ChatMessage&lt;/span&gt;(text: userText, isMe: &lt;span class="hljs-literal"&gt;true&lt;/span&gt;))

        &lt;span class="hljs-comment"&gt;// Launch a concurrent Task to call the API without blocking the UI&lt;/span&gt;
        &lt;span class="hljs-type"&gt;Task&lt;/span&gt; {
            await fetchAIResponse(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: userText)
        }
    }

    &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;fetchAIResponse&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt; text: String)&lt;/span&gt;&lt;/span&gt; async {
        isLoading = &lt;span class="hljs-literal"&gt;true&lt;/span&gt;

        &lt;span class="hljs-keyword"&gt;do&lt;/span&gt; {
            &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; reply = &lt;span class="hljs-keyword"&gt;try&lt;/span&gt; await service.sendMessage(text)
            &lt;span class="hljs-comment"&gt;// MainActor.run ensures this UI update definitely runs on main thread&lt;/span&gt;
            await &lt;span class="hljs-type"&gt;MainActor&lt;/span&gt;.run {
                messages.append(&lt;span class="hljs-type"&gt;ChatMessage&lt;/span&gt;(text: reply, isMe: &lt;span class="hljs-literal"&gt;false&lt;/span&gt;))
                isLoading = &lt;span class="hljs-literal"&gt;false&lt;/span&gt;
            }
        } &lt;span class="hljs-keyword"&gt;catch&lt;/span&gt; {
            await &lt;span class="hljs-type"&gt;MainActor&lt;/span&gt;.run {
                messages.append(
                    &lt;span class="hljs-type"&gt;ChatMessage&lt;/span&gt;(text: &lt;span class="hljs-string"&gt;"Something went wrong. Please try again."&lt;/span&gt;, isMe: &lt;span class="hljs-literal"&gt;false&lt;/span&gt;)
                )
                isLoading = &lt;span class="hljs-literal"&gt;false&lt;/span&gt;
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="key-concepts"&gt;Key concepts&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@MainActor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A global actor that confines all method calls and property access to the main thread. Applying it to a class means every method in the class is automatically dispatched to the main thread — no &lt;code&gt;DispatchQueue.main.async&lt;/code&gt; needed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ObservableObject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Makes this class publishable. SwiftUI subscribes to it automatically via &lt;code&gt;@StateObject&lt;/code&gt;/&lt;code&gt;@ObservedObject&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Published&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wraps a stored property so changes emit through a Combine publisher. Any subscribed View re-renders.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;final class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prevents subclassing — a best practice for ViewModels since they are never meant to be subclassed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;guard !userText.isEmpty else { return }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;strong&gt;guard statement&lt;/strong&gt; checks a condition and exits the current scope if it fails. The &lt;code&gt;else&lt;/code&gt; clause must exit (return, throw, break, etc.). It's the idiomatic Swift way to validate preconditions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Task { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates a new concurrent unit of work. Here it detaches the async API call from the synchronous &lt;code&gt;send()&lt;/code&gt; method.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;async/await&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Swift Concurrency model. &lt;code&gt;async&lt;/code&gt; marks a function that can suspend. &lt;code&gt;await&lt;/code&gt; suspends the caller until the async function returns. No callback hell, no completion handlers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;do { try await } catch { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Error handling for async throwing functions. &lt;code&gt;try await&lt;/code&gt; calls an &lt;code&gt;async throws&lt;/code&gt; function; any thrown error is caught in &lt;code&gt;catch&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;await MainActor.run { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Explicitly hops back to the main thread for a block of code. Useful inside a non-&lt;code&gt;@MainActor&lt;/code&gt; async context.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trimmingCharacters(in: .whitespaces)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes leading/trailing whitespace from a &lt;code&gt;String&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h3 id="geminiservice-swift-networking"&gt;GeminiService.swift — Networking&lt;/h3&gt;
&lt;p&gt;This is the &lt;strong&gt;Networking sublayer&lt;/strong&gt; of the ViewModel layer. It handles all HTTP communication with the Gemini API.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; Foundation

final &lt;span class="hljs-keyword"&gt;class&lt;/span&gt; GeminiService {

    private &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; apiKey = &lt;span class="hljs-string"&gt;"&amp;lt;api_key&amp;gt;"&lt;/span&gt;
    private &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; baseURL = &lt;span class="hljs-string"&gt;"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-flash-preview:generateContent"&lt;/span&gt;

    &lt;span class="hljs-comment"&gt;// `async throws` — this function is both asynchronous and can fail&lt;/span&gt;
    func sendMessage(&lt;span class="hljs-number"&gt;_&lt;/span&gt; message: String) async &lt;span class="hljs-meta"&gt;throws&lt;/span&gt; -&amp;gt; String {
        guard &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; url = URL(string: baseURL) &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
            &lt;span class="hljs-keyword"&gt;throw&lt;/span&gt; URLError(.badURL)   &lt;span class="hljs-comment"&gt;// throw stops execution; caller must catch&lt;/span&gt;
        }

        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; systemPrompt = &lt;span class="hljs-string"&gt;"""
        You are a helpful financial education assistant for beginner investors in India.
        ... (full system prompt)
        """&lt;/span&gt;

        &lt;span class="hljs-comment"&gt;// Build the JSON request body as a Swift dictionary&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; body: [String: Any] = [
            &lt;span class="hljs-string"&gt;"contents"&lt;/span&gt;: [
                [
                    &lt;span class="hljs-string"&gt;"parts"&lt;/span&gt;: [
                        [&lt;span class="hljs-string"&gt;"text"&lt;/span&gt;: systemPrompt + &lt;span class="hljs-string"&gt;"\nUser question: \(message)"&lt;/span&gt;]
                    ]
                ]
            ]
        ]

        &lt;span class="hljs-comment"&gt;// Serialize dictionary → Data (JSON bytes)&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; jsonData = &lt;span class="hljs-keyword"&gt;try&lt;/span&gt; JSONSerialization.data(withJSONObject: body)

        &lt;span class="hljs-comment"&gt;// Construct the HTTP request&lt;/span&gt;
        var request = URLRequest(url: url)
        request.httpMethod = &lt;span class="hljs-string"&gt;"POST"&lt;/span&gt;
        request.setValue(apiKey, forHTTPHeaderField: &lt;span class="hljs-string"&gt;"x-goog-api-key"&lt;/span&gt;)
        request.setValue(&lt;span class="hljs-string"&gt;"application/json"&lt;/span&gt;, forHTTPHeaderField: &lt;span class="hljs-string"&gt;"Content-Type"&lt;/span&gt;)
        request.httpBody = jsonData

        &lt;span class="hljs-comment"&gt;// Perform the network call — suspends until the response arrives&lt;/span&gt;
        &lt;span class="hljs-comment"&gt;// Returns (Data, URLResponse) — we only need Data here&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; (data, &lt;span class="hljs-number"&gt;_&lt;/span&gt;) = &lt;span class="hljs-keyword"&gt;try&lt;/span&gt; await URLSession.&lt;span class="hljs-keyword"&gt;shared&lt;/span&gt;.data(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: request)

        &lt;span class="hljs-comment"&gt;// Decode the JSON response into our Model struct&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; response = &lt;span class="hljs-keyword"&gt;try&lt;/span&gt; JSONDecoder().decode(GeminiResponse.self, from: data)

        &lt;span class="hljs-comment"&gt;// Navigate the nested response structure to get the text&lt;/span&gt;
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; response.candidates.first?.content.parts.first?.text ?? &lt;span class="hljs-string"&gt;"No response"&lt;/span&gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="network-request-lifecycle"&gt;Network request lifecycle&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-selector-tag"&gt;1&lt;/span&gt;. &lt;span class="hljs-selector-tag"&gt;Build&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;URL&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;from&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;string&lt;/span&gt;          →  &lt;span class="hljs-selector-tag"&gt;URL&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;string&lt;/span&gt;:)
&lt;span class="hljs-selector-tag"&gt;2&lt;/span&gt;. &lt;span class="hljs-selector-tag"&gt;Build&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;request&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;dictionary&lt;/span&gt;  →  &lt;span class="hljs-selector-attr"&gt;[String: Any]&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;3&lt;/span&gt;. &lt;span class="hljs-selector-tag"&gt;Serialize&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;to&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;JSON&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;bytes&lt;/span&gt;        →  &lt;span class="hljs-selector-tag"&gt;JSONSerialization&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.data&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;withJSONObject&lt;/span&gt;:)
&lt;span class="hljs-selector-tag"&gt;4&lt;/span&gt;. &lt;span class="hljs-selector-tag"&gt;Configure&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;URLRequest&lt;/span&gt;           →  &lt;span class="hljs-selector-tag"&gt;httpMethod&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;headers&lt;/span&gt;, &lt;span class="hljs-selector-tag"&gt;httpBody&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;5&lt;/span&gt;. &lt;span class="hljs-selector-tag"&gt;Execute&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;request&lt;/span&gt;                →  &lt;span class="hljs-selector-tag"&gt;URLSession&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.shared&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.data&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;for&lt;/span&gt;:)   ← &lt;span class="hljs-selector-tag"&gt;suspends&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;here&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;6&lt;/span&gt;. &lt;span class="hljs-selector-tag"&gt;Decode&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;response&lt;/span&gt;                →  &lt;span class="hljs-selector-tag"&gt;JSONDecoder&lt;/span&gt;()&lt;span class="hljs-selector-class"&gt;.decode&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;_&lt;/span&gt;:&lt;span class="hljs-attribute"&gt;from&lt;/span&gt;:)
&lt;span class="hljs-selector-tag"&gt;7&lt;/span&gt;. &lt;span class="hljs-selector-tag"&gt;Return&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;extracted&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;text&lt;/span&gt;          →  &lt;span class="hljs-selector-tag"&gt;optional&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;chaining&lt;/span&gt; + &lt;span class="hljs-selector-tag"&gt;nil&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;coalescing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="key-concepts"&gt;Key concepts&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;URLRequest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Represents a single HTTP request — method, headers, body, timeout, cache policy.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;URLSession.shared&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The default singleton session. Uses the system's networking stack, respects system proxy settings, handles cookies, caching.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.data(for: request)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Async version of the network call. Returns &lt;code&gt;(Data, URLResponse)&lt;/code&gt; — the raw response bytes and metadata.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;JSONSerialization.data(withJSONObject:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Converts a Foundation object graph (&lt;code&gt;[String: Any]&lt;/code&gt;) to JSON-encoded &lt;code&gt;Data&lt;/code&gt;. Used when you need dynamic/arbitrary JSON structures.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;JSONDecoder().decode(_:from:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Decodes JSON &lt;code&gt;Data&lt;/code&gt; into a &lt;code&gt;Decodable&lt;/code&gt; struct. Type-safe, compile-time checked. Preferred over &lt;code&gt;JSONSerialization&lt;/code&gt; for known response shapes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;request.setValue(_:forHTTPHeaderField:)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets an HTTP header. Here sets &lt;code&gt;Content-Type: application/json&lt;/code&gt; and the Google API key.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;throw URLError(.badURL)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Throws an error immediately. &lt;code&gt;URLError&lt;/code&gt; is the standard Foundation error for URL-related failures.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optional chaining (&lt;code&gt;?.&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;response.candidates.first?.content.parts.first?.text&lt;/code&gt; — safely navigates a chain; returns &lt;code&gt;nil&lt;/code&gt; at the first &lt;code&gt;nil&lt;/code&gt; without crashing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nil coalescing (&lt;code&gt;?? "No response"&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Provides a default value if the left side is &lt;code&gt;nil&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id="models-layer"&gt;Models Layer&lt;/h2&gt;
&lt;h3 id="chatmessagemodel-swift"&gt;ChatMessageModel.swift&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;import Foundation

&lt;span class="hljs-comment"&gt;// A single chat message — conforms to three protocols&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;ChatMessage&lt;/span&gt;&lt;/span&gt;: Codable, Identifiable {
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; id: UUID          &lt;span class="hljs-comment"&gt;// Identifiable requires an `id`&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; text: &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; isMe: Bool        &lt;span class="hljs-comment"&gt;// true = user bubble, false = AI bubble&lt;/span&gt;

    &lt;span class="hljs-comment"&gt;// Custom init provides a default UUID so callers don't have to supply one&lt;/span&gt;
    init(id: UUID = UUID(), text: &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, isMe: Bool) {
        &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.id = id
        &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.text = text
        &lt;span class="hljs-keyword"&gt;self&lt;/span&gt;.isMe = isMe
    }
}

&lt;span class="hljs-comment"&gt;// Nested Decodable structs mirror the JSON response structure from Gemini&lt;/span&gt;
&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;GeminiResponse&lt;/span&gt;&lt;/span&gt;: Decodable {
    &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; candidates: [Candidate]

    &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;Candidate&lt;/span&gt;&lt;/span&gt;: Decodable {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; content: Content
    }

    &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;Content&lt;/span&gt;&lt;/span&gt;: Decodable {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; parts: [Part]
    }

    &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;struct&lt;/span&gt; &lt;span class="hljs-title"&gt;Part&lt;/span&gt;&lt;/span&gt;: Decodable {
        &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; text: &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;GeminiResponse&lt;/code&gt; structure mirrors the actual JSON returned by the Gemini API:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-json"&gt;{
  &lt;span class="hljs-attr"&gt;"candidates"&lt;/span&gt;: [
    {
      &lt;span class="hljs-attr"&gt;"content"&lt;/span&gt;: {
        &lt;span class="hljs-attr"&gt;"parts"&lt;/span&gt;: [
          { &lt;span class="hljs-attr"&gt;"text"&lt;/span&gt;: &lt;span class="hljs-string"&gt;"Apple Inc. is a global technology company..."&lt;/span&gt; }
        ]
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Swift's &lt;code&gt;JSONDecoder&lt;/code&gt; automatically maps JSON keys to struct property names, recursively decoding nested objects.&lt;/p&gt;
&lt;h3 id="key-protocols-codable-identifiable-decodable"&gt;Key Protocols: Codable, Identifiable, Decodable&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Identifiable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Requires an &lt;code&gt;id&lt;/code&gt; property. Enables use in &lt;code&gt;ForEach&lt;/code&gt; without explicitly specifying the key path.&lt;/td&gt;
&lt;td&gt;Any model displayed in a list.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Codable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Combines &lt;code&gt;Encodable&lt;/code&gt; (Swift → JSON) and &lt;code&gt;Decodable&lt;/code&gt; (JSON → Swift). The compiler auto-synthesises the implementation if all properties are themselves &lt;code&gt;Codable&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Models that are both sent to and received from an API, or persisted to disk.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Decodable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSON → Swift only. No encoding needed.&lt;/td&gt;
&lt;td&gt;API response models you never need to serialise back.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Encodable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Swift → JSON only.&lt;/td&gt;
&lt;td&gt;Request bodies, local storage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Hashable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enables use in sets, dictionary keys, and &lt;code&gt;NavigationPath&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Route enums, identifiers.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="uuid"&gt;UUID&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;UUID&lt;/code&gt; generates a universally unique identifier — a 128-bit value guaranteed to be unique. &lt;code&gt;UUID()&lt;/code&gt; generates a new one each time. It conforms to &lt;code&gt;Codable&lt;/code&gt;, &lt;code&gt;Hashable&lt;/code&gt;, and &lt;code&gt;Identifiable&lt;/code&gt;-friendly, making it the standard choice for model IDs in Swift.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;let&lt;/span&gt; id = UUID()
&lt;span class="hljs-comment"&gt;// Example: 550E8400-E29B-41D4-A716-446655440000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;
&lt;h3 id="assets-xcassets"&gt;Assets.xcassets&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;Assets.xcassets&lt;/code&gt; &lt;strong&gt;asset catalog&lt;/strong&gt; is the central store for all visual assets in an iOS app. It is not just a folder — Xcode reads it at build time to generate optimised asset bundles for each device.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What goes in it:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Asset Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;App Icon&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AppIcon&lt;/code&gt; — set of icons at various resolutions for different devices (1x, 2x, 3x)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Image Sets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each image set holds 1x/2x/3x variants. SwiftUI/UIKit automatically loads the right one for the screen density.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Color Sets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Named colours with Light Mode and Dark Mode variants. Reference in code as &lt;code&gt;Color("MyColor")&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Symbol Configurations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SF Symbols customisation.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;How to use image assets in SwiftUI:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// From the asset catalog&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;Image&lt;/span&gt;(&lt;span class="hljs-string"&gt;"logo"&lt;/span&gt;)

&lt;span class="hljs-comment"&gt;// SF Symbols (Apple's built-in icon library — no assets needed)&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;Image&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;systemName&lt;/span&gt;: &lt;span class="hljs-string"&gt;"arrow.up.circle.fill"&lt;/span&gt;)
    &lt;span class="hljs-selector-class"&gt;.font&lt;/span&gt;(.system(&lt;span class="hljs-attribute"&gt;size&lt;/span&gt;: &lt;span class="hljs-number"&gt;32&lt;/span&gt;))
    &lt;span class="hljs-selector-class"&gt;.foregroundStyle&lt;/span&gt;(.blue)

&lt;span class="hljs-comment"&gt;// Resizable image that fills its frame&lt;/span&gt;
&lt;span class="hljs-selector-tag"&gt;Image&lt;/span&gt;(&lt;span class="hljs-string"&gt;"background"&lt;/span&gt;)
    &lt;span class="hljs-selector-class"&gt;.resizable&lt;/span&gt;()
    &lt;span class="hljs-selector-class"&gt;.scaledToFill&lt;/span&gt;()
    &lt;span class="hljs-selector-class"&gt;.frame&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;width&lt;/span&gt;: &lt;span class="hljs-number"&gt;100&lt;/span&gt;, &lt;span class="hljs-attribute"&gt;height&lt;/span&gt;: &lt;span class="hljs-number"&gt;100&lt;/span&gt;)
    &lt;span class="hljs-selector-class"&gt;.clipped&lt;/span&gt;()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;How to add a named colour and use it:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// In code (after defining "BrandBlue" in Assets.xcassets)&lt;/span&gt;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-title"&gt;Color&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-string"&gt;"BrandBlue"&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;

&lt;span class="hljs-comment"&gt;// Or use a Color extension (common pattern)&lt;/span&gt;
extension Color {
    static let brand = Color(&lt;span class="hljs-string"&gt;"BrandBlue"&lt;/span&gt;)
}

&lt;span class="hljs-function"&gt;&lt;span class="hljs-title"&gt;Text&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-string"&gt;"Hello"&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;.foregroundColor(.brand)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3 id="googleservice-info-plist"&gt;GoogleService-Info.plist&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;plist&lt;/code&gt; (Property List) is an XML-based key-value configuration file. Apple uses them extensively throughout iOS development.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GoogleService-Info.plist&lt;/code&gt; is the Firebase configuration file that contains:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-xml"&gt;&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;key&lt;/span&gt;&amp;gt;&lt;/span&gt;PROJECT_ID&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;key&lt;/span&gt;&amp;gt;&lt;/span&gt;       &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;string&lt;/span&gt;&amp;gt;&lt;/span&gt;finsightai&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;string&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;key&lt;/span&gt;&amp;gt;&lt;/span&gt;GOOGLE_APP_ID&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;key&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;string&lt;/span&gt;&amp;gt;&lt;/span&gt;1:xxx:ios:xxx&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;string&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;key&lt;/span&gt;&amp;gt;&lt;/span&gt;API_KEY&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;key&lt;/span&gt;&amp;gt;&lt;/span&gt;          &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;string&lt;/span&gt;&amp;gt;&lt;/span&gt;AIzaSy...&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;string&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;key&lt;/span&gt;&amp;gt;&lt;/span&gt;GCM_SENDER_ID&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;key&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;string&lt;/span&gt;&amp;gt;&lt;/span&gt;12345&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;string&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When &lt;code&gt;FirebaseApp.configure()&lt;/code&gt; is called in &lt;code&gt;AppDelegate&lt;/code&gt;, Firebase reads this file from the app bundle to identify the project and initialise all services (Analytics, Crashlytics, Cloud Messaging, etc.).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Other common plist uses in iOS:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Info.plist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;App-wide permissions (camera, location), URL schemes, version numbers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GoogleService-Info.plist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Firebase project configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom &lt;code&gt;.plist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;App configuration constants, feature flags, API base URLs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Reading a custom plist in Swift:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Reading from a custom Config.plist&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;guard&lt;/span&gt; &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; path = &lt;span class="hljs-type"&gt;Bundle&lt;/span&gt;.main.path(forResource: &lt;span class="hljs-string"&gt;"Config"&lt;/span&gt;, ofType: &lt;span class="hljs-string"&gt;"plist"&lt;/span&gt;),
      &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; dict = &lt;span class="hljs-type"&gt;NSDictionary&lt;/span&gt;(contentsOfFile: path),
      &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; apiKey = dict[&lt;span class="hljs-string"&gt;"API_KEY"&lt;/span&gt;] &lt;span class="hljs-keyword"&gt;as&lt;/span&gt;? &lt;span class="hljs-type"&gt;String&lt;/span&gt; &lt;span class="hljs-keyword"&gt;else&lt;/span&gt; {
    &lt;span class="hljs-built_in"&gt;fatalError&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Config.plist missing or malformed"&lt;/span&gt;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="routes-navigation"&gt;Routes — Navigation&lt;/h2&gt;
&lt;h3 id="route-swift"&gt;Route.swift&lt;/h3&gt;
&lt;p&gt;Navigation in modern SwiftUI (iOS 16+) is handled via &lt;code&gt;NavigationStack&lt;/code&gt; and &lt;code&gt;NavigationPath&lt;/code&gt;. FinSightAI centralises all navigation logic in a single &lt;code&gt;Route&lt;/code&gt; class.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; SwiftUI
&lt;span class="hljs-keyword"&gt;import&lt;/span&gt; Combine

&lt;span class="hljs-comment"&gt;// final = cannot be subclassed&lt;/span&gt;
&lt;span class="hljs-comment"&gt;// ObservableObject = SwiftUI can observe and react to changes&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;final&lt;/span&gt; &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;Route&lt;/span&gt;: &lt;span class="hljs-title"&gt;ObservableObject&lt;/span&gt; &lt;/span&gt;{

    &lt;span class="hljs-comment"&gt;// NavigationPath is a type-erased stack of Hashable values&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;// It drives the NavigationStack in FinSightAIApp&lt;/span&gt;
    @&lt;span class="hljs-type"&gt;Published&lt;/span&gt; &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; navPath = &lt;span class="hljs-type"&gt;NavigationPath&lt;/span&gt;()

    &lt;span class="hljs-comment"&gt;// All possible routes in the app as a type-safe enum&lt;/span&gt;
    &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;enum&lt;/span&gt; &lt;span class="hljs-title"&gt;RouteName&lt;/span&gt;: &lt;span class="hljs-title"&gt;Hashable&lt;/span&gt;, &lt;span class="hljs-title"&gt;Codable&lt;/span&gt; &lt;/span&gt;{
        &lt;span class="hljs-keyword"&gt;case&lt;/span&gt; home
        &lt;span class="hljs-keyword"&gt;case&lt;/span&gt; settings
        &lt;span class="hljs-keyword"&gt;case&lt;/span&gt; about
    }

    &lt;span class="hljs-comment"&gt;// Push a new screen onto the navigation stack&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;push&lt;/span&gt;&lt;span class="hljs-params"&gt;(path: RouteName)&lt;/span&gt;&lt;/span&gt; {
        navPath.append(path)
    }

    &lt;span class="hljs-comment"&gt;// Go back one screen&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;pop&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        navPath.removeLast()
    }

    &lt;span class="hljs-comment"&gt;// Go back to the root screen&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;popToRoot&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
        navPath.removeLast(navPath.&lt;span class="hljs-built_in"&gt;count&lt;/span&gt;)
    }

    &lt;span class="hljs-comment"&gt;// Go back N screens&lt;/span&gt;
    &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;func&lt;/span&gt; &lt;span class="hljs-title"&gt;popTill&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-built_in"&gt;count&lt;/span&gt;: Int)&lt;/span&gt;&lt;/span&gt; {
        navPath.removeLast(&lt;span class="hljs-built_in"&gt;count&lt;/span&gt;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;How to navigate from any view:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;struct&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;SomeView&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;View&lt;/span&gt; {
    &lt;span class="hljs-comment"&gt;// Retrieve the Route object from the environment&lt;/span&gt;
    &lt;span class="hljs-variable"&gt;@EnvironmentObject&lt;/span&gt; var &lt;span class="hljs-attribute"&gt;route&lt;/span&gt;: Route

    var &lt;span class="hljs-attribute"&gt;body&lt;/span&gt;: some View {
        &lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Open Settings"&lt;/span&gt;) {
            &lt;span class="hljs-selector-tag"&gt;route&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.push&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;path&lt;/span&gt;: .settings)    &lt;span class="hljs-comment"&gt;// navigates to SettingsScreen&lt;/span&gt;
        }

        &lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Go Home"&lt;/span&gt;) {
            &lt;span class="hljs-selector-tag"&gt;route&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.popToRoot&lt;/span&gt;()              &lt;span class="hljs-comment"&gt;// pops entire stack&lt;/span&gt;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3 id="navigationstack-navigationpath"&gt;NavigationStack &amp;amp; NavigationPath&lt;/h3&gt;
&lt;p&gt;Before iOS 16, SwiftUI had &lt;code&gt;NavigationView&lt;/code&gt; which was limited and buggy. iOS 16 introduced &lt;code&gt;NavigationStack&lt;/code&gt; — a complete redesign.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Root app structure (from FinSightAIApp.swift)&lt;/span&gt;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-title"&gt;NavigationStack&lt;/span&gt;&lt;span class="hljs-params"&gt;(path: &lt;span class="hljs-variable"&gt;$route&lt;/span&gt;.navPath)&lt;/span&gt;&lt;/span&gt; {    &lt;span class="hljs-comment"&gt;// path drives the stack&lt;/span&gt;
    HomeScreen()
        .navigationDestination(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: Route&lt;span class="hljs-selector-class"&gt;.RouteName&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.self&lt;/span&gt;) { destination &lt;span class="hljs-keyword"&gt;in&lt;/span&gt;
            switch destination {
            case &lt;span class="hljs-selector-class"&gt;.home&lt;/span&gt;:     HomeScreen()
            case &lt;span class="hljs-selector-class"&gt;.settings&lt;/span&gt;: SettingsScreen()
            case &lt;span class="hljs-selector-class"&gt;.about&lt;/span&gt;:    AboutScreen()
            }
        }
}
.environmentObject(route)
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Old (&lt;code&gt;NavigationView&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;New (&lt;code&gt;NavigationStack&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Each link defines its own destination&lt;/td&gt;
&lt;td&gt;All destinations declared centrally in &lt;code&gt;.navigationDestination&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Programmatic navigation awkward&lt;/td&gt;
&lt;td&gt;Full control via &lt;code&gt;NavigationPath&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nested &lt;code&gt;NavigationView&lt;/code&gt; bugs&lt;/td&gt;
&lt;td&gt;Type-safe stack with &lt;code&gt;push/pop&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No &lt;code&gt;popToRoot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;navPath.removeLast(navPath.count)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The flow:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. &lt;span class="hljs-selector-tag"&gt;Route&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.push&lt;/span&gt;(&lt;span class="hljs-selector-tag"&gt;path&lt;/span&gt;: &lt;span class="hljs-selector-class"&gt;.settings&lt;/span&gt;)
         │
         ▼
2. &lt;span class="hljs-selector-tag"&gt;navPath&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.append&lt;/span&gt;(&lt;span class="hljs-selector-tag"&gt;Route&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.RouteName&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.settings&lt;/span&gt;)
         │
         ▼
3. &lt;span class="hljs-selector-tag"&gt;NavigationStack&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;detects&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;navPath&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;changed&lt;/span&gt;
         │
         ▼
4. &lt;span class="hljs-selector-tag"&gt;Looks&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;up&lt;/span&gt; &lt;span class="hljs-selector-class"&gt;.navigationDestination&lt;/span&gt;(&lt;span class="hljs-selector-tag"&gt;for&lt;/span&gt;: &lt;span class="hljs-selector-tag"&gt;Route&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.RouteName&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.self&lt;/span&gt;)
         │
         ▼
5. &lt;span class="hljs-selector-tag"&gt;Renders&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;SettingsScreen&lt;/span&gt;() &lt;span class="hljs-selector-tag"&gt;on&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;top&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;of&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;the&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;stack&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="additional-navigation-modifiers-used-in-the-app"&gt;Additional navigation modifiers used in the app&lt;/h4&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-comment"&gt;// Sets the navigation bar title for the current screen&lt;/span&gt;
&lt;span class="hljs-selector-class"&gt;.navigationTitle&lt;/span&gt;(&lt;span class="hljs-string"&gt;"FinSight AI"&lt;/span&gt;)

&lt;span class="hljs-comment"&gt;// Controls the size of the navigation title (inline = small, automatic = large)&lt;/span&gt;
&lt;span class="hljs-selector-class"&gt;.navigationBarTitleDisplayMode&lt;/span&gt;(.large)

&lt;span class="hljs-comment"&gt;// Adds a button to the navigation bar&lt;/span&gt;
&lt;span class="hljs-selector-class"&gt;.toolbar&lt;/span&gt; {
    &lt;span class="hljs-selector-tag"&gt;ToolbarItem&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;placement&lt;/span&gt;: .navigationBarTrailing) {
        &lt;span class="hljs-selector-tag"&gt;Button&lt;/span&gt;(&lt;span class="hljs-string"&gt;"About"&lt;/span&gt;) { &lt;span class="hljs-selector-tag"&gt;route&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.push&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;path&lt;/span&gt;: .about) }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id="data-flow-end-to-end"&gt;Data Flow: End-to-End&lt;/h2&gt;
&lt;p&gt;Here is the complete flow when a user types "Reliance" and taps Send:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-number"&gt;1&lt;/span&gt;. [User]        Types &lt;span class="hljs-string"&gt;"Reliance"&lt;/span&gt; into TextField
                 → TextField bound to &lt;span class="hljs-variable"&gt;$chatModel&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.inputText&lt;/span&gt; via two-way Binding

&lt;span class="hljs-number"&gt;2&lt;/span&gt;. [User]        Taps the send Button
                 → Button calls chatModel.send()

&lt;span class="hljs-number"&gt;3&lt;/span&gt;. [ChatViewModel.send()]
                 → Trims whitespace, checks not empty (guard)
                 → Clears inputText (&lt;span class="hljs-string"&gt;""&lt;/span&gt;)
                 → Appends ChatMessage(text: &lt;span class="hljs-string"&gt;"Reliance"&lt;/span&gt;, isMe: true) to messages
                 → @Published messages fires → View re-renders → user bubble appears
                 → Launches Task { await fetchAIResponse(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: &lt;span class="hljs-string"&gt;"Reliance"&lt;/span&gt;) }

&lt;span class="hljs-number"&gt;4&lt;/span&gt;. [ChatViewModel.fetchAIResponse()]
                 → Sets isLoading = true → @Published fires → spinner appears
                 → Calls try await service.sendMessage(&lt;span class="hljs-string"&gt;"Reliance"&lt;/span&gt;)

&lt;span class="hljs-number"&gt;5&lt;/span&gt;. [GeminiService.sendMessage()]
                 → Constructs URL from baseURL string
                 → Builds JSON &lt;span class="hljs-selector-tag"&gt;body&lt;/span&gt; dict with systemPrompt + user message
                 → JSONSerialization encodes dict → Data
                 → Builds URLRequest: POST, API key &lt;span class="hljs-selector-tag"&gt;header&lt;/span&gt;, Content-Type &lt;span class="hljs-selector-tag"&gt;header&lt;/span&gt;
                 → try await URLSession&lt;span class="hljs-selector-class"&gt;.shared&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.data&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;for&lt;/span&gt;: request) ← suspends
                 → Gemini API processes and returns JSON response
                 → Resumes with (Data, URLResponse)
                 → JSONDecoder decodes Data → GeminiResponse struct
                 → Returns response&lt;span class="hljs-selector-class"&gt;.candidates&lt;/span&gt;[&lt;span class="hljs-number"&gt;0&lt;/span&gt;]&lt;span class="hljs-selector-class"&gt;.content&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.parts&lt;/span&gt;[&lt;span class="hljs-number"&gt;0&lt;/span&gt;]&lt;span class="hljs-selector-class"&gt;.text&lt;/span&gt;

&lt;span class="hljs-number"&gt;6&lt;/span&gt;. [Back &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; fetchAIResponse()]
                 → Receives reply String
                 → await MainActor&lt;span class="hljs-selector-class"&gt;.run&lt;/span&gt; { ... }
                 → Appends ChatMessage(text: reply, isMe: false) to messages
                 → Sets isLoading = false
                 → @Published fires → View re-renders → AI bubble + MarkdownText appear

&lt;span class="hljs-number"&gt;7&lt;/span&gt;. [HomeScreen ScrollViewReader]
                 → .onChange(of: chatModel&lt;span class="hljs-selector-class"&gt;.messages&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.count&lt;/span&gt;) fires
                 → proxy.scrollTo(lastMessage&lt;span class="hljs-selector-class"&gt;.id&lt;/span&gt;, anchor: .&lt;span class="hljs-attribute"&gt;bottom&lt;/span&gt;)
                 → ScrollView animates to show the new AI response
&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;h2 id="key-swift-concepts-glossary"&gt;Key Swift Concepts Glossary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Definition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;struct&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Value type. Copied when assigned. Used for Views and Models in SwiftUI. Immutable by default.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reference type. Shared when assigned. Used for ViewModels (&lt;code&gt;ObservableObject&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;final&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prevents a class from being subclassed. Applied to ViewModels as a best practice.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@State&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Privately owned reactive value inside a View. Changes trigger re-render. For simple local UI state.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Binding&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A reference to a &lt;code&gt;@State&lt;/code&gt; value owned by a parent. Two-way; reads and writes the parent's value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@StateObject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates and owns an &lt;code&gt;ObservableObject&lt;/code&gt;. Lives as long as the owning view.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@ObservedObject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;References an &lt;code&gt;ObservableObject&lt;/code&gt; owned elsewhere. Observes it for changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@EnvironmentObject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieves an &lt;code&gt;ObservableObject&lt;/code&gt; injected into the SwiftUI environment via &lt;code&gt;.environmentObject()&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@Published&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Property wrapper on &lt;code&gt;ObservableObject&lt;/code&gt; properties. Emits a change event through Combine when set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@MainActor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confines code to the main thread. Applying to a class makes all its methods main-thread-safe.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;async&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Marks a function as asynchronous — it can suspend without blocking its thread.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;await&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Suspends the current task until the awaited async operation completes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;throws&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Marks a function as capable of throwing errors. Callers must use &lt;code&gt;try&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;guard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Evaluates a condition; the &lt;code&gt;else&lt;/code&gt; block must exit scope. Used for precondition validation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Codable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-synthesised JSON encode/decode. Combines &lt;code&gt;Encodable&lt;/code&gt; + &lt;code&gt;Decodable&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Identifiable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Requires an &lt;code&gt;id&lt;/code&gt; property. Enables &lt;code&gt;ForEach&lt;/code&gt; to track items uniquely.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;some View&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An opaque return type — "some specific View type the compiler knows about." Used for &lt;code&gt;body&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NavigationPath&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A type-erased stack that drives &lt;code&gt;NavigationStack&lt;/code&gt;. Push/pop to navigate programmatically.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Task { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates a new concurrent unit of work from synchronous context.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@discardableResult&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Suppresses the warning when a function's return value is not used.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;optional chaining (?.)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Safely accesses a property on an optional value; returns &lt;code&gt;nil&lt;/code&gt; if the optional is &lt;code&gt;nil&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nil coalescing (??)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Returns the left value if non-nil, otherwise returns the right default value.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;FinSightAI is a clean, production-quality example of a modern iOS MVVM app. Here is what each layer contributes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Files&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Views&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;HomeScreen&lt;/code&gt;, &lt;code&gt;SplashScreen&lt;/code&gt;, &lt;code&gt;ChatBubble&lt;/code&gt;, etc.&lt;/td&gt;
&lt;td&gt;Declare UI. Bind to ViewModel state. Forward user actions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ViewModels&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChatViewModel&lt;/code&gt;, &lt;code&gt;GeminiService&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Own app state (&lt;code&gt;@Published&lt;/code&gt;). Call API. Handle errors. Transform raw data for Views.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChatMessage&lt;/code&gt;, &lt;code&gt;GeminiResponse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pure data. No UIKit/SwiftUI imports. Fully portable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Assets.xcassets&lt;/code&gt;, &lt;code&gt;plist&lt;/code&gt; files&lt;/td&gt;
&lt;td&gt;Images, colours, icons, configuration constants.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Routes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Route.swift&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single source of truth for navigation. Push, pop, and popToRoot from anywhere via &lt;code&gt;@EnvironmentObject&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The most important principle is &lt;strong&gt;separation of concerns&lt;/strong&gt; — Views know nothing about HTTP, Models know nothing about navigation, and ViewModels never import SwiftUI directly. This makes each layer independently testable, reusable, and maintainable.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Based on the open-source &lt;a href="https://github.com/lkrjangid1/FinSightAI"&gt;FinSightAI&lt;/a&gt; project by Lokesh Jangid.&lt;/em&gt;&lt;/p&gt;
</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Android Activity Alias in Flutter</title><link>https://flutdev.blogspot.com/2026/02/android-activity-alias-in-flutter.html</link><category>Activity-alias</category><category>flutter</category><author>noreply@blogger.com (Lokesh Jangid)</author><pubDate>Sun, 8 Feb 2026 23:25:00 -0800</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7439341812408440578.post-5463847706235449148</guid><description>&lt;h3 id="create-multiple-app-icons-from-a-single-flutter-app-like-amazon-pay-"&gt;Create Multiple App Icons from a Single Flutter App (Like Amazon Pay)&lt;/h3&gt;
&lt;hr /&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Have you ever noticed that the &lt;strong&gt;Amazon app&lt;/strong&gt; installs only &lt;strong&gt;once&lt;/strong&gt;, but shows &lt;strong&gt;multiple icons&lt;/strong&gt; in the &lt;a data-preview="" href="https://www.google.com/search?ved=1t:260882&amp;amp;q=Android+app+drawer+images&amp;amp;bbid=7439341812408440578&amp;amp;bpid=5463847706235449148" target="_blank"&gt;Android app drawer&lt;/a&gt;—such as &lt;strong&gt;Amazon&lt;/strong&gt; and &lt;strong&gt;Amazon Pay&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;Each icon:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Opens a &lt;strong&gt;different screen&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Has &lt;strong&gt;different quick actions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Behaves like a &lt;strong&gt;separate mini-app&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is &lt;strong&gt;only one APK installed&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Storage usage is &lt;strong&gt;not duplicated&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This powerful Android capability is called:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a data-preview="" href="https://www.google.com/search?ved=1t:260882&amp;amp;q=Activity+Alias+Android&amp;amp;bbid=7439341812408440578&amp;amp;bpid=5463847706235449148" target="_blank"&gt;Activity Alias&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And yes—&lt;strong&gt;you can implement it inside a &lt;a data-preview="" href="https://www.google.com/search?ved=1t:260882&amp;amp;q=Flutter+app+development&amp;amp;bbid=7439341812408440578&amp;amp;bpid=5463847706235449148" target="_blank"&gt;Flutter app&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="what-is-android-activity-alias-"&gt;What is Android Activity Alias?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Activity Alias&lt;/strong&gt; is an &lt;a data-preview="" href="https://www.google.com/search?ved=1t:260882&amp;amp;q=define+Android+manifest+feature&amp;amp;bbid=7439341812408440578&amp;amp;bpid=5463847706235449148" target="_blank"&gt;Android manifest feature&lt;/a&gt; that allows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multiple &lt;strong&gt;launcher icons&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Different &lt;strong&gt;labels &amp;amp; icons&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Different &lt;strong&gt;entry activities&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;All from the &lt;strong&gt;same installed app&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So instead of:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-symbol"&gt;1 &lt;/span&gt;App → &lt;span class="hljs-number"&gt;1&lt;/span&gt; Launcher Icon
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You get:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-symbol"&gt;1 &lt;/span&gt;App → Multiple Launcher Icons → Multiple Entry Experiences
&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;h2 id="real-world-use-cases"&gt;Real-World Use Cases&lt;/h2&gt;
&lt;p&gt;Popular apps using this pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shopping + Payments separation&lt;/li&gt;
&lt;li&gt;Consumer + Business mode&lt;/li&gt;
&lt;li&gt;Lite tools inside a super-app&lt;/li&gt;
&lt;li&gt;Feature-focused entry points&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This improves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User retention&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature discoverability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversion to high-value flows (like payments)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id="concept-architecture"&gt;Concept Architecture&lt;/h2&gt;
&lt;p&gt;Internally, Android app structure looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Single APK
 ├── MainActivity        → Opens Home
 ├── PayActivity         → Opens Payments
 ├── Activity &lt;span class="hljs-keyword"&gt;Alias&lt;/span&gt; &lt;span class="hljs-string"&gt;#1&lt;/span&gt;   → Launcher icon &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; Main
 ├── Activity &lt;span class="hljs-keyword"&gt;Alias&lt;/span&gt; &lt;span class="hljs-string"&gt;#2&lt;/span&gt;   → Launcher icon &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; Pay
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each alias appears as a &lt;strong&gt;separate app icon&lt;/strong&gt;, but all share:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Same &lt;strong&gt;package&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Same &lt;strong&gt;permissions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Same &lt;strong&gt;data&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Same &lt;strong&gt;installation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id="visual-architecture-diagram-prompt-for-ai-image-generation-"&gt;Visual Architecture Diagram Prompt (for AI image generation)&lt;/h2&gt;
&lt;p&gt;Use this prompt to generate a clean architecture diagram:&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/-NBzE4Bi_VFs/aYmGVEi9n5I/AAAAAAAAfVQ/93Pw-Jo1MGgbkUhgDxoVBk0cCjS4XZcXQCNcBGAsYHQ/s512/Gemini_Generated_Image_6qyfk56qyfk56qyf.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" data-original-height="512" data-original-width="512" height="320" src="https://lh3.googleusercontent.com/-NBzE4Bi_VFs/aYmGVEi9n5I/AAAAAAAAfVQ/93Pw-Jo1MGgbkUhgDxoVBk0cCjS4XZcXQCNcBGAsYHQ/s320/Gemini_Generated_Image_6qyfk56qyfk56qyf.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 id="implementing-activity-alias-in-flutter"&gt;Implementing Activity Alias in Flutter&lt;/h1&gt;
&lt;p&gt;Flutter cannot directly create launcher aliases.
You must configure it in the &lt;strong&gt;&lt;a data-preview="" href="https://www.google.com/search?ved=1t:260882&amp;amp;q=define+Android+native+layer&amp;amp;bbid=7439341812408440578&amp;amp;bpid=5463847706235449148" target="_blank"&gt;Android native layer&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We’ll do this step-by-step.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="step-1-create-a-second-android-activity"&gt;Step 1 — Create a Second Android Activity&lt;/h2&gt;
&lt;p&gt;Open:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;android&lt;span class="hljs-regexp"&gt;/app/&lt;/span&gt;src&lt;span class="hljs-regexp"&gt;/main/&lt;/span&gt;AndroidManifest.xml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add a new activity:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-xml"&gt;&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;activity&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:name&lt;/span&gt;=&lt;span class="hljs-string"&gt;".PayActivity"&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:exported&lt;/span&gt;=&lt;span class="hljs-string"&gt;"true"&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:theme&lt;/span&gt;=&lt;span class="hljs-string"&gt;"@style/Theme.App"&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;activity&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This activity will later open a &lt;strong&gt;different Flutter route&lt;/strong&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="step-2-add-activity-alias-for-second-launcher-icon"&gt;Step 2 — Add Activity Alias for Second Launcher Icon&lt;/h2&gt;
&lt;pre&gt;&lt;code class="lang-xml"&gt;&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;activity-alias&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:name&lt;/span&gt;=&lt;span class="hljs-string"&gt;".PayLauncher"&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:enabled&lt;/span&gt;=&lt;span class="hljs-string"&gt;"true"&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:exported&lt;/span&gt;=&lt;span class="hljs-string"&gt;"true"&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:icon&lt;/span&gt;=&lt;span class="hljs-string"&gt;"@mipmap/ic_pay"&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:label&lt;/span&gt;=&lt;span class="hljs-string"&gt;"My Pay"&lt;/span&gt;
    &lt;span class="hljs-attr"&gt;android:targetActivity&lt;/span&gt;=&lt;span class="hljs-string"&gt;".PayActivity"&lt;/span&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;intent-filter&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;action&lt;/span&gt; &lt;span class="hljs-attr"&gt;android:name&lt;/span&gt;=&lt;span class="hljs-string"&gt;"android.intent.action.MAIN"&lt;/span&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;category&lt;/span&gt; &lt;span class="hljs-attr"&gt;android:name&lt;/span&gt;=&lt;span class="hljs-string"&gt;"android.intent.category.LAUNCHER"&lt;/span&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;intent-filter&lt;/span&gt;&amp;gt;&lt;/span&gt;

&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;activity-alias&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now Android will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Show &lt;strong&gt;another icon in app drawer&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Launch &lt;strong&gt;PayActivity&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Still keep &lt;strong&gt;single installation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id="launcher-result-illustration-prompt"&gt;Launcher Result Illustration Prompt&lt;/h2&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/-KEFJvRxaagg/aYmKxPnpx1I/AAAAAAAAfVc/TwP97atZn7wqJzraFGKiSOE_UP7K3lqkACNcBGAsYHQ/s512/Gemini_Generated_Image_emg02temg02temg0.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" data-original-height="512" data-original-width="512" height="320" src="https://lh3.googleusercontent.com/-KEFJvRxaagg/aYmKxPnpx1I/AAAAAAAAfVc/TwP97atZn7wqJzraFGKiSOE_UP7K3lqkACNcBGAsYHQ/s320/Gemini_Generated_Image_emg02temg02temg0.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h2 id="step-3-connect-payactivity-to-flutter-route"&gt;&lt;br /&gt;&lt;/h2&gt;&lt;h2 id="step-3-connect-payactivity-to-flutter-route"&gt;Step 3 — Connect PayActivity to Flutter Route&lt;/h2&gt;
&lt;p&gt;Create:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-selector-tag"&gt;PayActivity&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.kt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="lang-kotlin"&gt;&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;PayActivity&lt;/span&gt; : &lt;span class="hljs-type"&gt;FlutterActivity&lt;/span&gt;&lt;/span&gt;() {
    &lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;fun&lt;/span&gt; &lt;span class="hljs-title"&gt;getInitialRoute&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt;: String {
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-string"&gt;"/pay"&lt;/span&gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells Flutter:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“When launched from Pay icon → open &lt;code&gt;/pay&lt;/code&gt; screen.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id="step-4-handle-route-inside-flutter"&gt;Step 4 — Handle Route Inside Flutter&lt;/h2&gt;
&lt;pre&gt;&lt;code class="lang-dart"&gt;MaterialApp(
  &lt;span class="hljs-name"&gt;initialRoute&lt;/span&gt;: '/',
  routes: {
    '/': (&lt;span class="hljs-name"&gt;_&lt;/span&gt;) =&amp;gt; HomeScreen(),
    '/pay': (&lt;span class="hljs-name"&gt;_&lt;/span&gt;) =&amp;gt; PayScreen(),
  },
)&lt;span class="hljs-comment"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Done &#127881;&lt;/p&gt;
&lt;p&gt;You now have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Two app icons&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two independent entry flows&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One Flutter app&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id="user-flow-diagram-prompt"&gt;User Flow Diagram Prompt&lt;/h2&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/-7bNpgWnB2tM/aYmLDtsLcxI/AAAAAAAAfVo/Nqol0-_8LjoocA3keOvSSqZfULkWqHaZQCNcBGAsYHQ/s512/Gemini_Generated_Image_dobb1sdobb1sdobb.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" data-original-height="512" data-original-width="512" height="320" src="https://lh3.googleusercontent.com/-7bNpgWnB2tM/aYmLDtsLcxI/AAAAAAAAfVo/Nqol0-_8LjoocA3keOvSSqZfULkWqHaZQCNcBGAsYHQ/s320/Gemini_Generated_Image_dobb1sdobb1sdobb.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;h1 id="advanced-capabilities"&gt;Advanced Capabilities&lt;/h1&gt;
&lt;h2 id="1-enable-disable-icons-dynamically"&gt;1. Enable/Disable Icons Dynamically&lt;/h2&gt;
&lt;p&gt;You can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Show Pay icon &lt;strong&gt;only after login&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Hide feature-based icons&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;A/B experiments&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Controlled via:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-selector-tag"&gt;PackageManager&lt;/span&gt;&lt;span class="hljs-selector-class"&gt;.setComponentEnabledSetting&lt;/span&gt;()
&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;h2 id="2-separate-analytics-per-icon"&gt;2. Separate Analytics Per Icon&lt;/h2&gt;
&lt;p&gt;Track:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which launcher opened the app&lt;/li&gt;
&lt;li&gt;Conversion from &lt;strong&gt;Pay icon vs Home&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Feature adoption&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is &lt;strong&gt;huge for product teams&lt;/strong&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="3-white-label-mini-apps-inside-one-apk"&gt;3. White-Label Mini-Apps Inside One APK&lt;/h2&gt;
&lt;p&gt;Activity alias enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Partner-branded entry points&lt;/li&gt;
&lt;li&gt;Region-specific icons&lt;/li&gt;
&lt;li&gt;Campaign-based launchers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multiple builds&lt;/li&gt;
&lt;li&gt;Store re-submission&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id="product-strategy-illustration-prompt"&gt;Product Strategy Illustration Prompt&lt;/h2&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/-7i5v2nPvPZg/aYmLQFvFOdI/AAAAAAAAfVw/5Y0G_PbMf3ElB93KZISB5l1wA82Lqv6MgCNcBGAsYHQ/s512/Gemini_Generated_Image_33og4c33og4c33og.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" data-original-height="512" data-original-width="512" height="320" src="https://lh3.googleusercontent.com/-7i5v2nPvPZg/aYmLQFvFOdI/AAAAAAAAfVw/5Y0G_PbMf3ElB93KZISB5l1wA82Lqv6MgCNcBGAsYHQ/s320/Gemini_Generated_Image_33og4c33og4c33og.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;h1 id="android-vs-ios-limitation"&gt;Android vs iOS Limitation&lt;/h1&gt;
&lt;h3 id="android"&gt;Android&lt;/h3&gt;
&lt;p&gt;✔ Multiple launcher icons supported
✔ Separate quick actions per icon
✔ Same installation&lt;/p&gt;
&lt;h3 id="ios"&gt;iOS&lt;/h3&gt;
&lt;p&gt;❌ Multiple simultaneous icons not allowed
✔ Siri Shortcuts workaround
✔ Quick actions via long-press&lt;/p&gt;
&lt;p&gt;So &lt;strong&gt;true Activity Alias exists only on Android&lt;/strong&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id="when-should-you-use-activity-alias-"&gt;When Should You Use Activity Alias?&lt;/h1&gt;
&lt;p&gt;Use it when you want:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Faster access to &lt;strong&gt;high-value features&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a data-preview="" href="https://www.google.com/search?ved=1t:260882&amp;amp;q=define+Super-app+architecture&amp;amp;bbid=7439341812408440578&amp;amp;bpid=5463847706235449148" target="_blank"&gt;Super-app architecture&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Payment or scan flows to feel &lt;strong&gt;independent&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Better &lt;strong&gt;engagement &amp;amp; retention&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avoid if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;App is very small&lt;/li&gt;
&lt;li&gt;Features are not frequently used&lt;/li&gt;
&lt;li&gt;UX may feel confusing&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id="final-thoughts"&gt;Final Thoughts&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Android Activity Alias&lt;/strong&gt; is one of the most &lt;strong&gt;underused growth features&lt;/strong&gt; in mobile development.&lt;/p&gt;
&lt;p&gt;With just:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1 extra activity&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1 manifest alias&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1 Flutter route&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can transform a simple Flutter app into a &lt;strong&gt;multi-entry super-app experience&lt;/strong&gt;—just like major fintech and commerce platforms.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;If you'd like next, I can write:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic icon enable/disable in Flutter (production code)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a data-preview="" href="https://www.google.com/search?ved=1t:260882&amp;amp;q=Deep+linking+activity+alias+combined+architecture&amp;amp;bbid=7439341812408440578&amp;amp;bpid=5463847706235449148" target="_blank"&gt;Deep linking + activity alias combined architecture&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a data-preview="" href="https://www.google.com/search?ved=1t:260882&amp;amp;q=Super-app+design+system+for+Flutter&amp;amp;bbid=7439341812408440578&amp;amp;bpid=5463847706235449148" target="_blank"&gt;Super-app design system for Flutter&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just tell me.&lt;/p&gt;
</description><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://lh3.googleusercontent.com/-NBzE4Bi_VFs/aYmGVEi9n5I/AAAAAAAAfVQ/93Pw-Jo1MGgbkUhgDxoVBk0cCjS4XZcXQCNcBGAsYHQ/s72-c/Gemini_Generated_Image_6qyfk56qyfk56qyf.png" width="72"/><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Understanding Pigeon Methods in Flutter: A Complete Guide for Native Communication</title><link>https://flutdev.blogspot.com/2026/02/understanding-pigeon-methods-in-flutter.html</link><category>flutter</category><category>Pigeon</category><author>noreply@blogger.com (Lokesh Jangid)</author><pubDate>Tue, 3 Feb 2026 21:07:00 -0800</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7439341812408440578.post-5617594281210353252</guid><description>&lt;p&gt;Flutter is great—until you need to talk to native code.&lt;/p&gt;
&lt;p&gt;If you’ve ever used &lt;code&gt;MethodChannel&lt;/code&gt;, you’ve probably faced:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Runtime crashes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Map&amp;lt;dynamic, dynamic&amp;gt;&lt;/code&gt; casting errors&lt;/li&gt;
&lt;li&gt;Hard-to-debug contracts between Flutter and native&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pigeon&lt;/strong&gt; solves this problem by introducing &lt;strong&gt;type-safe, generated APIs&lt;/strong&gt; between Flutter and native platforms.&lt;/p&gt;
&lt;p&gt;This article explains &lt;strong&gt;Pigeon methods in detail&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What methods exist&lt;/li&gt;
&lt;li&gt;How they work on native side&lt;/li&gt;
&lt;li&gt;Who calls whom&lt;/li&gt;
&lt;li&gt;Sync vs async&lt;/li&gt;
&lt;li&gt;Real-world patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="what-is-pigeon-"&gt;What is Pigeon?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Pigeon&lt;/strong&gt; is a &lt;strong&gt;code generation tool&lt;/strong&gt; from the Flutter team that creates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dart APIs&lt;/li&gt;
&lt;li&gt;Kotlin / Java APIs (Android)&lt;/li&gt;
&lt;li&gt;Swift / Objective-C APIs (iOS)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All from &lt;strong&gt;one shared Dart file&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pigeon does &lt;strong&gt;not&lt;/strong&gt; render UI.
It enables &lt;strong&gt;safe, structured communication&lt;/strong&gt; between Flutter and native code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="the-core-concept-only-two-types-of-pigeon-methods"&gt;The Core Concept: Only Two Types of Pigeon Methods&lt;/h2&gt;
&lt;p&gt;Pigeon has &lt;strong&gt;exactly two method categories&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;HostApi&lt;/strong&gt; → Flutter calls Native&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FlutterApi&lt;/strong&gt; → Native calls Flutter&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s it. No third type.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-hostapi-methods-flutter-native-"&gt;1️⃣ HostApi Methods (Flutter → Native)&lt;/h2&gt;
&lt;h3 id="what-are-hostapi-methods-"&gt;What are HostApi methods?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Defined in Dart&lt;/li&gt;
&lt;li&gt;Implemented in native&lt;/li&gt;
&lt;li&gt;Called by Flutter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think of them as &lt;strong&gt;commands&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="use-cases"&gt;Use cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Start payment&lt;/li&gt;
&lt;li&gt;Fetch device info&lt;/li&gt;
&lt;li&gt;Open native screens&lt;/li&gt;
&lt;li&gt;Trigger SDK actions&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="dart-definition"&gt;Dart Definition&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-dart"&gt;&lt;span class="hljs-meta"&gt;@HostApi&lt;/span&gt;()
&lt;span class="hljs-keyword"&gt;abstract&lt;/span&gt; &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;PaymentHostApi&lt;/span&gt; &lt;/span&gt;{
  &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;void&lt;/span&gt; &lt;span class="hljs-title"&gt;startPayment&lt;/span&gt;&lt;span class="hljs-params"&gt;(String orderId)&lt;/span&gt;&lt;/span&gt;;
  &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;void&lt;/span&gt; &lt;span class="hljs-title"&gt;cancelPayment&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="generated-native-code-android-kotlin-"&gt;Generated Native Code (Android – Kotlin)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-kotlin"&gt;&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;interface&lt;/span&gt; &lt;span class="hljs-title"&gt;PaymentHostApi&lt;/span&gt; &lt;/span&gt;{
  &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;fun&lt;/span&gt; &lt;span class="hljs-title"&gt;startPayment&lt;/span&gt;&lt;span class="hljs-params"&gt;(orderId: &lt;span class="hljs-type"&gt;String&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;
  &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;fun&lt;/span&gt; &lt;span class="hljs-title"&gt;cancelPayment&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="native-implementation-your-code-"&gt;Native Implementation (Your Code)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-kotlin"&gt;&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;PaymentHostApiImpl&lt;/span&gt;&lt;/span&gt;(
  &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; &lt;span class="hljs-keyword"&gt;val&lt;/span&gt; activity: Activity
) : PaymentHostApi {

  &lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;fun&lt;/span&gt; &lt;span class="hljs-title"&gt;startPayment&lt;/span&gt;&lt;span class="hljs-params"&gt;(orderId: &lt;span class="hljs-type"&gt;String&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-comment"&gt;// Call native SDK (Juspay, Razorpay, etc.)&lt;/span&gt;
  }

  &lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;fun&lt;/span&gt; &lt;span class="hljs-title"&gt;cancelPayment&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt; {
    &lt;span class="hljs-comment"&gt;// Handle cancellation&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="key-characteristics"&gt;Key Characteristics&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;HostApi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Call direction&lt;/td&gt;
&lt;td&gt;Flutter → Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implemented by&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Used for&lt;/td&gt;
&lt;td&gt;Commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type safety&lt;/td&gt;
&lt;td&gt;✅ Compile-time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON parsing&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="2-flutterapi-methods-native-flutter-"&gt;2️⃣ FlutterApi Methods (Native → Flutter)&lt;/h2&gt;
&lt;h3 id="what-are-flutterapi-methods-"&gt;What are FlutterApi methods?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Defined in Dart&lt;/li&gt;
&lt;li&gt;Implemented in Flutter&lt;/li&gt;
&lt;li&gt;Called by native&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think of them as &lt;strong&gt;events or callbacks&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="use-cases"&gt;Use cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Payment status updates&lt;/li&gt;
&lt;li&gt;SDK lifecycle events&lt;/li&gt;
&lt;li&gt;Sensor updates&lt;/li&gt;
&lt;li&gt;Progress callbacks&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="dart-definition"&gt;Dart Definition&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-dart"&gt;&lt;span class="hljs-meta"&gt;@FlutterApi&lt;/span&gt;()
&lt;span class="hljs-keyword"&gt;abstract&lt;/span&gt; &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;PaymentFlutterApi&lt;/span&gt; &lt;/span&gt;{
  &lt;span class="hljs-keyword"&gt;void&lt;/span&gt; onPaymentSuccess(&lt;span class="hljs-built_in"&gt;String&lt;/span&gt; txnId);
  &lt;span class="hljs-keyword"&gt;void&lt;/span&gt; onPaymentFailure(&lt;span class="hljs-built_in"&gt;String&lt;/span&gt; reason);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="generated-native-class-android-kotlin-"&gt;Generated Native Class (Android – Kotlin)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-kotlin"&gt;&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;PaymentFlutterApi&lt;/span&gt;&lt;/span&gt;(
  &lt;span class="hljs-keyword"&gt;private&lt;/span&gt; &lt;span class="hljs-keyword"&gt;val&lt;/span&gt; binaryMessenger: BinaryMessenger
) {
  &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;fun&lt;/span&gt; &lt;span class="hljs-title"&gt;onPaymentSuccess&lt;/span&gt;&lt;span class="hljs-params"&gt;(txnId: &lt;span class="hljs-type"&gt;String&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt; {}
  &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;fun&lt;/span&gt; &lt;span class="hljs-title"&gt;onPaymentFailure&lt;/span&gt;&lt;span class="hljs-params"&gt;(reason: &lt;span class="hljs-type"&gt;String&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt; {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="calling-from-native"&gt;Calling from Native&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-kotlin"&gt;&lt;span class="hljs-attribute"&gt;val&lt;/span&gt; flutterApi = PaymentFlutterApi(binaryMessenger)

flutterApi.&lt;span class="hljs-literal"&gt;on&lt;/span&gt;PaymentSuccess(&lt;span class="hljs-string"&gt;"TXN12345"&lt;/span&gt;)
flutterApi.&lt;span class="hljs-literal"&gt;on&lt;/span&gt;PaymentFailure(&lt;span class="hljs-string"&gt;"Insufficient balance"&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="flutter-implementation"&gt;Flutter Implementation&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-dart"&gt;&lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;PaymentCallbacks&lt;/span&gt; &lt;span class="hljs-keyword"&gt;extends&lt;/span&gt; &lt;span class="hljs-title"&gt;PaymentFlutterApi&lt;/span&gt; &lt;/span&gt;{
  &lt;span class="hljs-meta"&gt;@override&lt;/span&gt;
  void onPaymentSuccess(&lt;span class="hljs-type"&gt;String&lt;/span&gt; txnId) {
    &lt;span class="hljs-comment"&gt;// Update Bloc / Cubit / State&lt;/span&gt;
  }

  &lt;span class="hljs-meta"&gt;@override&lt;/span&gt;
  void onPaymentFailure(&lt;span class="hljs-type"&gt;String&lt;/span&gt; reason) {
    &lt;span class="hljs-comment"&gt;// Show error UI&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="key-characteristics"&gt;Key Characteristics&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;FlutterApi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Call direction&lt;/td&gt;
&lt;td&gt;Native → Flutter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implemented by&lt;/td&gt;
&lt;td&gt;Flutter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Used for&lt;/td&gt;
&lt;td&gt;Events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time updates&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State friendly&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="visual-call-flow"&gt;Visual Call Flow&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://docs.flutter.dev/assets/images/docs/PlatformChannels.png" alt="Image"&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-selector-tag"&gt;Flutter&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;UI&lt;/span&gt;
   │
   │  &lt;span class="hljs-selector-tag"&gt;HostApi&lt;/span&gt; (command)
   ▼
&lt;span class="hljs-selector-tag"&gt;Native&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;SDK&lt;/span&gt;
   │
   │  &lt;span class="hljs-selector-tag"&gt;FlutterApi&lt;/span&gt; (event)
   ▼
&lt;span class="hljs-selector-tag"&gt;Flutter&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;State&lt;/span&gt; → &lt;span class="hljs-selector-tag"&gt;UI&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;rebuild&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="async-methods-in-pigeon"&gt;Async Methods in Pigeon&lt;/h2&gt;
&lt;p&gt;Pigeon supports async operations using &lt;code&gt;Future&lt;/code&gt; in Dart.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="dart"&gt;Dart&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-dart"&gt;&lt;span class="hljs-meta"&gt;@HostApi&lt;/span&gt;()
&lt;span class="hljs-keyword"&gt;abstract&lt;/span&gt; &lt;span class="hljs-class"&gt;&lt;span class="hljs-keyword"&gt;class&lt;/span&gt; &lt;span class="hljs-title"&gt;DeviceApi&lt;/span&gt; &lt;/span&gt;{
  Future&amp;lt;&lt;span class="hljs-built_in"&gt;String&lt;/span&gt;&amp;gt; getDeviceId();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="android-kotlin-"&gt;Android (Kotlin)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-kotlin"&gt;&lt;span class="hljs-keyword"&gt;override&lt;/span&gt; &lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;fun&lt;/span&gt; &lt;span class="hljs-title"&gt;getDeviceId&lt;/span&gt;&lt;span class="hljs-params"&gt;(result: &lt;span class="hljs-type"&gt;Result&lt;/span&gt;&amp;lt;&lt;span class="hljs-type"&gt;String&lt;/span&gt;&amp;gt;)&lt;/span&gt;&lt;/span&gt; {
  &lt;span class="hljs-keyword"&gt;try&lt;/span&gt; {
    result.success(&lt;span class="hljs-string"&gt;"ANDROID-DEVICE-001"&lt;/span&gt;)
  } &lt;span class="hljs-keyword"&gt;catch&lt;/span&gt; (e: Exception) {
    result.error(e)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="ios-swift-"&gt;iOS (Swift)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-swift"&gt;&lt;span class="hljs-selector-tag"&gt;func&lt;/span&gt; &lt;span class="hljs-selector-tag"&gt;getDeviceId&lt;/span&gt;(&lt;span class="hljs-attribute"&gt;completion&lt;/span&gt;: &lt;span class="hljs-variable"&gt;@escaping&lt;/span&gt; (Result&amp;lt;String, Error&amp;gt;) -&amp;gt; Void) {
  &lt;span class="hljs-selector-tag"&gt;completion&lt;/span&gt;(.success(&lt;span class="hljs-string"&gt;"IOS-DEVICE-001"&lt;/span&gt;))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="common-real-world-pattern-payments-example-"&gt;Common Real-World Pattern (Payments Example)&lt;/h2&gt;
&lt;h3 id="hostapi-flutter-native-"&gt;HostApi (Flutter → Native)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-dart"&gt;&lt;span class="hljs-keyword"&gt;void&lt;/span&gt; initiatePayment(&lt;span class="hljs-built_in"&gt;Map&lt;/span&gt;&amp;lt;&lt;span class="hljs-built_in"&gt;String&lt;/span&gt;, &lt;span class="hljs-built_in"&gt;String&lt;/span&gt;&amp;gt; payload);
&lt;span class="hljs-keyword"&gt;void&lt;/span&gt; exitSdk();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="flutterapi-native-flutter-"&gt;FlutterApi (Native → Flutter)&lt;/h3&gt;
&lt;pre&gt;&lt;code class="lang-dart"&gt;&lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;void&lt;/span&gt; &lt;span class="hljs-title"&gt;onTransactionSuccess&lt;/span&gt;&lt;span class="hljs-params"&gt;(String txnId)&lt;/span&gt;&lt;/span&gt;;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;void&lt;/span&gt; &lt;span class="hljs-title"&gt;onTransactionFailure&lt;/span&gt;&lt;span class="hljs-params"&gt;(String &lt;span class="hljs-keyword"&gt;error&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;;
&lt;span class="hljs-function"&gt;&lt;span class="hljs-keyword"&gt;void&lt;/span&gt; &lt;span class="hljs-title"&gt;onSdkClosed&lt;/span&gt;&lt;span class="hljs-params"&gt;()&lt;/span&gt;&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This pattern is used heavily in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Juspay&lt;/li&gt;
&lt;li&gt;Razorpay&lt;/li&gt;
&lt;li&gt;Paytm&lt;/li&gt;
&lt;li&gt;PhonePe&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="why-pigeon-is-better-than-methodchannel"&gt;Why Pigeon is Better Than MethodChannel&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;MethodChannel&lt;/th&gt;
&lt;th&gt;Pigeon&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Type safety&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compile-time errors&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON parsing&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refactoring safety&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large SDK support&lt;/td&gt;
&lt;td&gt;Painful&lt;/td&gt;
&lt;td&gt;Clean&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="mental-model-to-remember"&gt;Mental Model to Remember&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="hljs-variable"&gt;@HostApi&lt;/span&gt;     = Commands (Flutter → Native)
&lt;span class="hljs-variable"&gt;@FlutterApi&lt;/span&gt;  = Events   (Native → Flutter)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you understand this, you understand Pigeon.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-pigeon-does-not-do"&gt;What Pigeon Does NOT Do&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;❌ Render UI&lt;/li&gt;
&lt;li&gt;❌ Manage state&lt;/li&gt;
&lt;li&gt;❌ Replace Bloc / Cubit / Streams&lt;/li&gt;
&lt;li&gt;❌ Act as a real-time engine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It &lt;strong&gt;only&lt;/strong&gt; guarantees safe communication.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Pigeon is not magic—but it &lt;strong&gt;removes an entire class of bugs&lt;/strong&gt; from Flutter-native integration.&lt;/p&gt;
&lt;p&gt;If your app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Uses native SDKs&lt;/li&gt;
&lt;li&gt;Handles real-time callbacks&lt;/li&gt;
&lt;li&gt;Needs stability at scale&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&#128073; &lt;strong&gt;Pigeon is the correct solution.&lt;/strong&gt;&lt;/p&gt;
</description><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item></channel></rss>