<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mrugesh Tank</title>
    <description>The latest articles on DEV Community by Mrugesh Tank (@mrugeshtank).</description>
    <link>https://dev.to/mrugeshtank</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1151116%2F005a0f7b-5f4f-4e36-bcc5-d9b2cdd44688.png</url>
      <title>DEV Community: Mrugesh Tank</title>
      <link>https://dev.to/mrugeshtank</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrugeshtank"/>
    <language>en</language>
    <item>
      <title>SwiftUI Debugging: 6 Techniques Every iOS Dev Should Know</title>
      <dc:creator>Mrugesh Tank</dc:creator>
      <pubDate>Sat, 14 Mar 2026 08:27:03 +0000</pubDate>
      <link>https://dev.to/mrugeshtank/swiftui-debugging-6-techniques-every-ios-dev-should-know-p3h</link>
      <guid>https://dev.to/mrugeshtank/swiftui-debugging-6-techniques-every-ios-dev-should-know-p3h</guid>
      <description>&lt;p&gt;SwiftUI Previews are magical when they work. When they don't, &lt;br&gt;
staring at "Preview crashed" with no clue why is one of the &lt;br&gt;
most frustrating things in iOS development.&lt;/p&gt;

&lt;p&gt;After debugging thousands of preview crashes across multiple &lt;br&gt;
production apps, here are the 6 techniques I reach for every time.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Do SwiftUI Previews Break?
&lt;/h2&gt;

&lt;p&gt;Previews run in a &lt;strong&gt;sandboxed environment&lt;/strong&gt; separate from your app. &lt;br&gt;
They have stricter resource limits, no access to your app's &lt;br&gt;
environment by default, and their own compiler pipeline. &lt;br&gt;
Once you internalize this, most failures become predictable.&lt;/p&gt;

&lt;p&gt;Four root causes cover 90% of cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile-time errors (one broken file cascades across the project)&lt;/li&gt;
&lt;li&gt;Runtime errors (force unwraps, nil crashes)&lt;/li&gt;
&lt;li&gt;Missing environment dependencies (environmentObject not injected)&lt;/li&gt;
&lt;li&gt;Complexity/timeout (view does too much, exceeds preview's time limit)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Technique 1 — Build explicitly first
&lt;/h2&gt;

&lt;p&gt;Hit &lt;code&gt;Cmd+B&lt;/code&gt; before anything else. The preview compiler sometimes &lt;br&gt;
fails silently while your main target builds fine. Check the build &lt;br&gt;
output for errors in files you weren't even editing.&lt;/p&gt;


&lt;h2&gt;
  
  
  Technique 2 — &lt;code&gt;Self._printChanges()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This underused API tells you &lt;strong&gt;exactly&lt;/strong&gt; why SwiftUI re-evaluated &lt;br&gt;
your view's body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_printChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// your view...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The console will log which &lt;code&gt;@State&lt;/code&gt; or &lt;code&gt;@ObservedObject&lt;/code&gt; property &lt;br&gt;
changed and triggered the re-render. Invaluable for infinite &lt;br&gt;
re-render loops.&lt;/p&gt;


&lt;h2&gt;
  
  
  Technique 3 — Use &lt;code&gt;Logger&lt;/code&gt;, not &lt;code&gt;print()&lt;/code&gt;
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;OSLog&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ProfileView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;subsystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"com.yourapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nv"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"ProfileView"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"body evaluated"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// your view...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Logger is type-safe, shows up in Console.app with filtering, &lt;br&gt;
and gets stripped from release builds automatically.&lt;/p&gt;


&lt;h2&gt;
  
  
  Technique 4 — Isolate by binary search
&lt;/h2&gt;

&lt;p&gt;Comment out &lt;strong&gt;half&lt;/strong&gt; your view body. If preview works → problem is &lt;br&gt;
in the commented half. Still crashes → problem is in the remaining &lt;br&gt;
half. Keep halving until you find the exact line.&lt;/p&gt;

&lt;p&gt;If you can't isolate a view without breaking everything, &lt;br&gt;
your components are too tightly coupled. That's the real bug.&lt;/p&gt;


&lt;h2&gt;
  
  
  Technique 5 — Inject mock dependencies
&lt;/h2&gt;

&lt;p&gt;Never make real network calls from previews. Use protocol-based &lt;br&gt;
injection so you can swap in a mock:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;DataFetching&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MockDataFetcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DataFetching&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Mrugesh Tank"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"m@test.com"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;#Preview {&lt;/span&gt;
    &lt;span class="kt"&gt;UserListView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dataFetcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MockDataFetcher&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Technique 6 — Centralize preview mock data
&lt;/h2&gt;

&lt;p&gt;Instead of scattering mock objects across every preview block, &lt;br&gt;
create a single &lt;code&gt;PreviewHelpers.swift&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;PreviewData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Test User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;member&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your previews become clean and consistent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="cp"&gt;#Preview { ProfileView(user: PreviewData.user) }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Bigger Lesson
&lt;/h2&gt;

&lt;p&gt;Views that preview reliably are almost always well-architected views. &lt;br&gt;
Preview instability is usually a symptom of tight coupling, &lt;br&gt;
missing dependency injection, or views doing too much.&lt;/p&gt;

&lt;p&gt;The path to stable previews is the same as the path to &lt;br&gt;
maintainable, testable SwiftUI code.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I wrote a more detailed version of this with additional &lt;br&gt;
patterns on my blog:&lt;/em&gt;&lt;br&gt;
👉 &lt;a href="https://idiotswithios.com/swiftui-debugging-powerful-mind-blowing-ways/" rel="noopener noreferrer"&gt;Full article on idiots With iOS&lt;/a&gt;&lt;/p&gt;

</description>
      <category>swiftui</category>
      <category>ios</category>
      <category>swift</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
