<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Sofapps · Blog</title>
  <subtitle>Articles, tutorials and news about building apps for Apple platforms, in English and Italian.</subtitle>
  <link href="https://www.sofapps.it/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://www.sofapps.it/blog/" rel="alternate" type="text/html"/>
  <id>https://www.sofapps.it/feed.xml</id>
  <updated>2025-09-02T00:00:00Z</updated>
  <icon>https://www.sofapps.it/assets/images/favicon-32x32.png</icon>
  <entry>
    <title>Liquid Glass vs Material 3: The End of Convergence in Mobile Design</title>
    <link href="https://www.sofapps.it/blog/liquid-glass-vs-material-3/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/liquid-glass-vs-material-3/</id>
    <published>2025-09-02T00:00:00Z</published>
    <updated>2025-09-02T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Swift"/>
    <category term="WWDC25"/>
    <category term="Xcode 26"/>
    <category term="iOS 26"/>
    <category term="Liquid Glass"/>
    <category term="Google"/>
    <category term="Material 3"/>
    <category term="Expressive"/>
    <category term="Editorial"/>
    <summary>Since iOS 7 and Material Design, Apple and Google had been moving toward similar flat visual languages. Liquid Glass bets on a sensory, spatial future, while Material 3 Expressive uses bold color, variable type and elastic motion for today's users. For developers this ends neutrality: the options are native UI with shared logic, adaptive cross-platform frameworks, or a brand-first design.</summary>
    <content type="html">&lt;p&gt;2025 has forever changed the aesthetics of the mobile world.&lt;/p&gt;
&lt;p&gt;Apple unveiled &lt;strong&gt;Liquid Glass&lt;/strong&gt;, a digital meta-material bringing transparency, refraction, and dynamism to iOS, iPadOS, and macOS.&lt;/p&gt;
&lt;p&gt;Google responded with &lt;strong&gt;Material 3 Expressive&lt;/strong&gt;, the evolution of Material You, built around bold colors, variable typography, and elastic animations.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Two visions that couldn’t be more different. And with them, the end of an era: the era of aesthetic convergence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;a-step-back-when-paths-seemed-aligned&quot;&gt;A Step Back: When Paths Seemed Aligned&lt;/h3&gt;
&lt;p&gt;To understand the significance of today’s divergence, we need to go back more than a decade.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;iOS 7&lt;/strong&gt; (2013), Apple permanently shelved skeuomorphism: goodbye to wood and leather textures, hello to thin typography, flat surfaces, and subtle transparency.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig001-480.avif 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig001-960.avif 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig001-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig001-480.webp 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig001-960.webp 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig001-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig001.webp&quot; alt=&quot;The iOS 7 World Clock screen with thin type, a flat red Edit button and a plain analog clock&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Just a year later, Google introduced &lt;strong&gt;Material Design&lt;/strong&gt;, a visual language inspired by &lt;strong&gt;“digital paper”&lt;/strong&gt;, capable of moving and gaining depth through shadows and elevation.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig002-480.avif 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig002-960.avif 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig002-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig002-480.webp 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig002-960.webp 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig002-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig002.webp&quot; alt=&quot;A Google presenter on stage in front of a large slide that reads Material Design&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;At that moment, the two paths seemed parallel. Minimalism, clarity, and motion design were shared values, and for third-party developers, it finally looked possible to imagine a consistent cross-platform experience.&lt;/p&gt;
&lt;h2 id=&quot;the-illusion-of-neutrality&quot;&gt;The Illusion of Neutrality&lt;/h2&gt;
&lt;p&gt;The aesthetic convergence of those years fueled tools like &lt;strong&gt;Flutter&lt;/strong&gt; or &lt;strong&gt;React Native&lt;/strong&gt;, which could offer interfaces that looked at home on both iOS and Android.&lt;/p&gt;
&lt;p&gt;But adoption was uneven: Android’s fragmentation slowed the spread of Material Design, while iOS’s stricter guidelines accelerated alignment.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig003-480.avif 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig003-960.avif 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig003-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig003-480.webp 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig003-960.webp 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig003-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig003.webp&quot; alt=&quot;Two lock screens side by side: iOS with a thin clock and slide to unlock, and Android with a colorful geometric wallpaper&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;For years, the impression was that of a nearly universal visual language. But today, the trajectory has shifted, a lot.&lt;/p&gt;
&lt;h2 id=&quot;liquid-glass-apple-bets-on-a-sensory-future&quot;&gt;Liquid Glass: Apple Bets on a Sensory Future&lt;/h2&gt;
&lt;p&gt;With &lt;strong&gt;Liquid Glass&lt;/strong&gt;, Apple moves beyond flat minimalism: three- dimensional surfaces, light refraction, dynamic transparency.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig004-480.avif 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig004-960.avif 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig004-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig004-480.webp 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig004-960.webp 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig004-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig004.webp&quot; alt=&quot;Liquid Glass controls on a grid: glass sliders, a plus button, a capsule menu with three symbols and a transparent pill&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;It’s an aesthetic clearly pointing toward the future of &lt;strong&gt;spatial computing&lt;/strong&gt; and continuity with &lt;strong&gt;visionOS&lt;/strong&gt;, weaving a direct thread between smartphone, tablet, desktop, and headset.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig005-480.avif 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig005-960.avif 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig005-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig005-480.webp 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig005-960.webp 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig005-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig005.webp&quot; alt=&quot;A glass capsule lens on top of a blue slider, refracting the track below it&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;A sensory, almost physical design language — one built for the long term.&lt;/p&gt;
&lt;h2 id=&quot;material-3-expressive-google-s-take-on-the-present&quot;&gt;Material 3 Expressive: Google’s Take on the Present&lt;/h2&gt;
&lt;p&gt;Google, in contrast, pushes its visual language forward with &lt;strong&gt;Material 3 Expressive&lt;/strong&gt;, embracing a bolder, more immediate direction.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig006-480.avif 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig006-960.avif 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig006-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig006-480.webp 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig006-960.webp 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig006-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig006.webp&quot; alt=&quot;A pattern of rounded Material 3 Expressive buttons in bright blue and lilac, with icons and labels such as Play, Send and Flex&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Saturated colors, variable typography, elastic animations: an aesthetic that speaks to &lt;strong&gt;Gen Z&lt;/strong&gt;, emphasizing accessibility and visual impact in the short term.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig007-480.avif 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig007-960.avif 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig007-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig007-480.webp 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig007-960.webp 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig007-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig007.webp&quot; alt=&quot;A Material 3 Expressive email composer in lilac tones, with From and To fields in a condensed and a bold rounded typeface&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Not the future of the metaverse or mixed reality, but a lively, everyday, and inclusive design system.&lt;/p&gt;
&lt;h2 id=&quot;consequences-for-developers-and-brands&quot;&gt;Consequences for Developers and Brands&lt;/h2&gt;
&lt;p&gt;This divergence is more than just a shift in style — it marks the &lt;strong&gt;end of neutrality&lt;/strong&gt; for app development.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig008-480.avif 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig008-960.avif 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig008-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig008-480.webp 480w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig008-960.webp 960w, https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig008-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/liquid-glass-vs-material-3/liquidglassvsmaterial3fig008.webp&quot; alt=&quot;An iPhone with Control Center in Liquid Glass next to an Android phone with Material quick settings in purple&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;The choices are now threefold:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native UI with shared logic&lt;/strong&gt; → maximum aesthetic fidelity to each platform’s guidelines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adaptive cross-frameworks&lt;/strong&gt; → branching and skinning to respect stylistic differences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brand-first approach&lt;/strong&gt; → increasingly chosen by major players, imposing their identity above OS rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, the challenge is no longer writing a single codebase, but translating one design system into two different dialects — without losing coherence or usability.&lt;/p&gt;
&lt;h2 id=&quot;a-new-aesthetic-competition&quot;&gt;A New Aesthetic Competition&lt;/h2&gt;
&lt;p&gt;Liquid Glass and Material 3 Expressive embody two opposite philosophies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Apple&lt;/strong&gt; bets on the future, with a sensory interface paving the way for spatial computing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google&lt;/strong&gt; optimizes the present, with vibrant, accessible design tuned for today’s users.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For users, this means experiences ever more defined by their chosen ecosystem.&lt;/p&gt;
&lt;p&gt;For developers, it means making sharp, unavoidable choices about whether to adapt — or differentiate.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Once again, design is not just aesthetics. It is competitive strategy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&quot;video-embed&quot; data-youtube=&quot;nkvg3QdaufM&quot; style=&quot;background-image: url('/blog/liquid-glass-vs-material-3/youtube-nkvg3QdaufM-480.webp')&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=nkvg3QdaufM&quot; data-title=&quot;YouTube&quot;&gt;&lt;span class=&quot;video-play&quot; aria-hidden=&quot;true&quot;&gt;&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M8 5v14l11-7z&quot;/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;video-label&quot;&gt;YouTube&lt;/span&gt;&lt;span class=&quot;video-note&quot;&gt;Plays on YouTube. Nothing is loaded until you click.&lt;/span&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;—
Happy coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>WWDC25: Hello, Liquid Glass</title>
    <link href="https://www.sofapps.it/blog/wwdc25-liquid-glass/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/wwdc25-liquid-glass/</id>
    <published>2025-06-23T00:00:00Z</published>
    <updated>2025-06-23T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Swift"/>
    <category term="WWDC25"/>
    <category term="Xcode 26"/>
    <category term="iOS 26"/>
    <category term="Liquid Glass"/>
    <category term="Editorial"/>
    <summary>Liquid Glass, announced at WWDC25, unifies iOS, macOS, iPadOS, watchOS, visionOS and tvOS under one visual language. The post traces the path from the skeuomorphism of the first iPhone to the flat design of iOS 7 and Material Design, then argues that glass is a coherent, readable metaphor for layered interfaces and spatial computing, as Craig Federighi explained.</summary>
    <content type="html">&lt;p&gt;Among the standout announcements from &lt;strong&gt;WWDC25&lt;/strong&gt;, one of the most impactful is without a doubt Apple’s new design system, paired with a reimagined user experience and fresh interface paradigms.&lt;/p&gt;
&lt;p&gt;We’re talking about &lt;strong&gt;Liquid Glass&lt;/strong&gt; — Apple’s latest design language unveiled in early June. This new system effectively unifies the entire suite of Apple operating systems under a single visual paradigm. The goal? To ensure unprecedented continuity and fluidity across iOS, macOS, iPadOS, watchOS, visionOS, and even tvOS.&lt;/p&gt;
&lt;p&gt;To truly grasp the scale of this shift, it’s useful to take a step back in time — all the way to 2007, when the very first iPhone was introduced.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Origins of Skeuomorphism&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To bring that revolutionary device to life — a smartphone made almost entirely of a 3.5-inch touchscreen — Steve Jobs and his team opted for a visual interface grounded in skeuomorphism. This was a deliberate decision from Jobs himself, who believed it was critical to give users the sense they were interacting with familiar, now-touchable objects. Skeuomorphism uses graphical elements that mimic real-world items to create instant recognizability.&lt;/p&gt;
&lt;p&gt;The calculator looked like a physical calculator; the Notes app featured yellow ruled lines like a real notepad; the Calendar resembled a leather-bound planner. Every detail was crafted to make interaction feel as intuitive as possible.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/ipad-skeu001-480.avif 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/ipad-skeu001-960.avif 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/ipad-skeu001-1024.avif 1024w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/ipad-skeu001-480.webp 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/ipad-skeu001-960.webp 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/ipad-skeu001-1024.webp 1024w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/ipad-skeu001.jpg&quot; alt=&quot;The iPad Calendar app in 2011, with a leather binding, torn paper edges and stitched details&quot; width=&quot;1024&quot; height=&quot;768&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;At the time, no one had ever used a fully touch-based smartphone. Competing devices clumsily combined screens with physical keyboards. Jobs wanted something radically different, and skeuomorphism proved a winning idea. Buttons appeared three-dimensional, complete with shadows and highlights, encouraging users to tap. No stylus, no physical keys — just tap, swipe, and pinch.&lt;/p&gt;
&lt;p&gt;The term skeuomorphism originates from Greek:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;σκεῦος&lt;/strong&gt; (skeuos) = tool, vessel&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;μορφή&lt;/strong&gt; (morphē) = form&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In essence: &lt;em&gt;“an object that retains the appearance of an older or more familiar object, despite serving a modern and different function.”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The physical world offers plenty of analogies: ceramic vases that mimic metal, concrete pillars styled after marble, decorative buttons on jackets that no longer fasten anything but recall functional closures.&lt;/p&gt;
&lt;p&gt;By the 1980s, the concept had entered the digital world. As graphical user interfaces emerged, designers sought a visual language that could resonate with millions of new users. Apple was among the first to adopt this approach: folder icons, the Trash bin, even the Finder™ were early skeuomorphic elements. These evolved in the early 2000s into the now-iconic &lt;strong&gt;AQUA&lt;/strong&gt; interface of MacOS X.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/aqua0001-480.avif 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/aqua0001-960.avif 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/aqua0001-1024.avif 1024w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/aqua0001-480.webp 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/aqua0001-960.webp 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/aqua0001-1024.webp 1024w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/aqua0001.jpg&quot; alt=&quot;A Mac OS X Aqua desktop with a Finder window, iTunes, a calculator, translucent menus and a Dock with glossy icons&quot; width=&quot;1024&quot; height=&quot;768&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Skeuomorphism didn’t originate with the iPhone — but it found its fullest expression there, thanks in large part to Scott Forstall under Jobs’ leadership, who between 2007 and 2009 solidified its presence in iPhoneOS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Many agree that the early success of the iPhone was largely owed to this revolutionary visual choice. The skeuomorphic interface reigned for six years, maturing and becoming a reference point for independent developers who, during that golden age of the App Store, produced apps of remarkable quality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Rise of Jony Ive’s Minimalism&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In 2013, with iOS 7, Apple abandoned skeuomorphism in favor of a flat, minimalist design language introduced by Jony Ive. Everything became two-dimensional, essential — and, at times, monotonous. The initial interface needed refinement: low contrast, ambiguous interactive elements, and overly saturated colors drew criticism. It took a few years before this new language evolved into something cohesive and appreciated.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/ios70001-480.avif 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/ios70001-960.avif 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/ios70001-1600.avif 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/ios70001-480.webp 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/ios70001-960.webp 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/ios70001-1600.webp 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/ios70001.jpg&quot; alt=&quot;Two iOS 7 screenshots side by side: the flat Notes app and the Calendar app with thin type and white backgrounds&quot; width=&quot;2494&quot; height=&quot;2208&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Apple wasn’t alone in this transition. Minimalist design found its way into other ecosystems too — first through Microsoft’s brief foray into mobile, and especially through Google’s Material Design, which expanded on the ideas of iOS 7. Over time, Apple would borrow several ideas back from Google to evolve its interface, culminating in the maturity now seen in iOS 18 — twelve years later.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/material0001-480.avif 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/material0001-960.avif 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/material0001-1600.avif 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/material0001-480.webp 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/material0001-960.webp 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/material0001-1600.webp 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/material0001.jpg&quot; alt=&quot;Three Android phones showing Material Design apps with teal, orange and purple color themes, cards, radio buttons and a floating action button&quot; width=&quot;1992&quot; height=&quot;1309&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Time for Change&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Eighteen years after the iPhone’s debut, the devices we carry in our pockets are full-fledged computers, with capabilities once thought impossible. Minimalist interfaces — even when enhanced with animations and transitions — now feel overly simplistic for such advanced hardware.&lt;/p&gt;
&lt;p&gt;That’s why Apple’s decision today makes perfect sense: sacrificing a small portion of processing power to make interfaces feel more alive, expressive, and ready for the spatial computing era. It marks the beginning of a new cycle.&lt;/p&gt;
&lt;p&gt;Why the long backstory? Because Liquid Glass represents a shift comparable in magnitude to that of skeuomorphism. It borrows its core ideas, reinterprets them, and encapsulates them in a new symbolic material: &lt;strong&gt;glass&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/liquidglass0001-480.avif 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/liquidglass0001-960.avif 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/liquidglass0001-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/liquidglass0001-480.webp 480w, https://www.sofapps.it/blog/wwdc25-liquid-glass/liquidglass0001-960.webp 960w, https://www.sofapps.it/blog/wwdc25-liquid-glass/liquidglass0001-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/wwdc25-liquid-glass/liquidglass0001.jpg&quot; alt=&quot;Liquid Glass controls on a grid: transparent glass sliders, a menu with three options, a plus button and glass capsules&quot; width=&quot;1400&quot; height=&quot;788&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;As Craig Federighi explained in an interview with the Wall Street Journal, glass is the perfect metaphor for an interface designed for spatial computing and augmented reality — based on the overlaying of layers. But to make those layers useful, you need a system that’s &lt;strong&gt;coherent&lt;/strong&gt;, &lt;strong&gt;readable&lt;/strong&gt;, and &lt;strong&gt;usable&lt;/strong&gt; across both touch and non-touch devices.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Glass meets those needs: it’s transparent, reflective, fluid. It allows users to see through layers while maintaining focus on foreground elements — preserving environmental continuity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This concept will take time to mature. But one thing is certain: Apple has chosen its direction — and done so with consistency. This fall, we’ll see its first concrete implementations.&lt;/p&gt;
&lt;p&gt;Welcome, Liquid Glass.&lt;/p&gt;
&lt;p&gt;—
Happy coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Dynamic Island: Neverland and the new iPhone 14 Pro</title>
    <link href="https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/</id>
    <published>2022-09-08T00:00:00Z</published>
    <updated>2022-09-08T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="Editorial"/>
    <category term="Dynamic Island"/>
    <category term="iOS"/>
    <category term="iPhone 14"/>
    <category term="Events"/>
    <summary>With iPhone 14 Pro Apple replaces the notch with the Dynamic Island, an area around the sensors that becomes part of the interface. The author retraces the notch since iPhone X in 2017, compares it with the iPhone 4 bumper story and reads the new design as a successful merge of hardware and software. He concludes that innovating also means turning a limitation into something real.</summary>
    <content type="html">&lt;p&gt;A stroke of genius. A move nobody expected. Not even the most hardened leakers had grasped the essence of that magic hole which, until a couple of hours earlier, was rumored to take some not well identified digital shape.&lt;/p&gt;
&lt;p&gt;Hundreds of words and minutes spent talking about it. The defeatists were already ready to announce the end of Apple, which would lose its distinctive brand: &lt;em&gt;the notch&lt;/em&gt;. Someone more cultured wondered whether this choice had not led to dangerous asymmetries and cognitive difficulties with the content shown on screen. Someone else swore to have proof that the notch would become an &lt;em&gt;&lt;strong&gt;i&lt;/strong&gt;&lt;/em&gt; of iPhone turned on its side.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;One thing is certain. Nobody managed to take away from Tim Cook and his Apple an astonishing surprise effect.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So here we are, admiring in awe and speechless the latest masterstroke from Apple at its event of yesterday, 7 September 2022: the &lt;strong&gt;Dynamic Island&lt;/strong&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/dynamic-island-animation.gif&quot; alt=&quot;Animation of the Dynamic Island at the top of an iPhone 14 Pro, with the Lock Screen showing the time 9:41&quot; width=&quot;444&quot; height=&quot;444&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/figure&gt;
&lt;p&gt;A concept that clearly shows how Apple's design evolves over the years following a precise script, and never at random.&lt;/p&gt;
&lt;p&gt;In 2017 &lt;em&gt;(5 years ago, ed.)&lt;/em&gt; Apple announced the iPhone X to the world, the first device with a notch, a cutout at the top center of the screen meant to house the bulky sensors for face recognition and the front camera. The choice was heavily debated and caught the eye of the specialized IT press with a mix of approval and dissent, as always, I would add.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/notch-parody-480.avif 480w, https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/notch-parody-960.avif 960w, https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/notch-parody-1200.avif 1200w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/notch-parody-480.webp 480w, https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/notch-parody-960.webp 960w, https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/notch-parody-1200.webp 1200w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/notch-parody.jpg&quot; alt=&quot;On the left an iPhone X with a notch held up in front of a New York street, on the right a still from an ad showing two men looking at their phones&quot; width=&quot;1200&quot; height=&quot;674&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;At the time OLED displays were already a hot topic and iPhone X had one. We have since seen 4 more revisions of this notch, through Xs, 11, 12 and 13. In the latest revisions its size was slightly reduced and over these 5 years it has become a bit part of us: a unique identity of the Apple brand and of the iPhone. Copied in countless attempts by the competition, but never matched in its stupid and absolute simplicity.&lt;/p&gt;
&lt;p&gt;It is 2022 and the time is ripe to go beyond. The display on the new iPhone 14 Pro has a peak contrast ratio of 2,000,000 : 1 and blacks as pure as ever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is time, in short, to make creative those holes in the screen that remain indispensable to host sensors and cameras.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Technology is now ready to turn into magic, to give the user the feeling that those holes are not an obstacle but, on the contrary, a feature that makes the experience on the new iPhone more fluid and unforgettable.&lt;/p&gt;
&lt;p&gt;It makes me smile because, in this too, I find an analogy with the philosophy of the beloved and late Steve Jobs, who turned a hardware problem on the iPhone 4 into a killer feature, giving birth to the market of cases and bumpers.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/iphone-bumper-400.avif 400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/iphone-bumper-400.webp 400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/dynamic-island-iphone-14-pro/iphone-bumper.jpg&quot; alt=&quot;Steve Jobs on stage next to a pink iPhone 4 bumper priced at $29&quot; width=&quot;400&quot; height=&quot;300&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;What can I say? The result of this dynamic island suddenly makes everything look old. Any existing version of the notch suddenly takes us back well over 5 years, making the whole experience around it feel dated.&lt;/p&gt;
&lt;p&gt;An Apple ad I am very fond of comes to mind, which in my opinion perfectly captures the process of conceiving and building this masterpiece of synergy between hardware and software.&lt;/p&gt;
&lt;figure class=&quot;video-embed&quot; data-youtube=&quot;LcGPI2tV2yY&quot; style=&quot;background-image: url('/blog/dynamic-island-iphone-14-pro/youtube-LcGPI2tV2yY-480.webp')&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=LcGPI2tV2yY&quot; data-title=&quot;YouTube&quot;&gt;&lt;span class=&quot;video-play&quot; aria-hidden=&quot;true&quot;&gt;&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M8 5v14l11-7z&quot;/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span class=&quot;video-label&quot;&gt;YouTube&lt;/span&gt;&lt;span class=&quot;video-note&quot;&gt;Plays on YouTube. Nothing is loaded until you click.&lt;/span&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;There is a lot of loose talk that today's Apple no longer knows how to innovate and that there is not much more to get out of our smartphones. In part it is true: we are at the edge of an island and, sooner or later, we will have to set sail to look for other lands.&lt;/p&gt;
&lt;p&gt;Knowing how to innovate is also this: seeing something on the horizon that is not there and turning it into a real, tangible island.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>App Tracking Transparency using Combine</title>
    <link href="https://www.sofapps.it/blog/app-tracking-transparency-combine/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/app-tracking-transparency-combine/</id>
    <published>2021-05-04T00:00:00Z</published>
    <updated>2021-05-04T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Swift"/>
    <category term="Combine"/>
    <category term="Tutorial"/>
    <summary>Since iOS 14.5 an app must ask the user for permission before reading the advertising identifier. The post wraps ATTrackingManager and ASIdentifierManager in an ATTrackingHelper that conforms to ObservableObject and publishes the authorization status and the identifier with @Published, and shows it used from a SwiftUI view. It also covers the NSUserTrackingUsageDescription entry in Info.plist.</summary>
    <content type="html">&lt;p&gt;One of the most publicized feature coming with iOS14.5 is the new App Tracking Trasparency feature. There are plenty of articles around that aim to pinpoint the relevant positions in this decision from Apple and counterparts like Facebook. I don’t want to digging out the political aspect of this feature. Instead, I would like to quickly overview what you need to work with this brand new capability and what this means in terms of technology underground.&lt;/p&gt;
&lt;p&gt;App Tracking Trasparency consists of one piece of software in the form of a class named: &lt;strong&gt;ATTrackingManager&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ATTrackingManager&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; NSObject&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Apple states that this class provides all what you need to ask for permission and get the current status of your request. This class collaborates together with the Ad framework in order to identify anonymously users and let track their habits / interests.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackingmanager-workflow-480.avif 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackingmanager-workflow-960.avif 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackingmanager-workflow-1600.avif 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackingmanager-workflow-480.webp 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackingmanager-workflow-960.webp 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackingmanager-workflow-1600.webp 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackingmanager-workflow.png&quot; alt=&quot;Diagram: ATTrackingManager provides the AuthorizationStatus and ASIdentifierManager provides the advertisingIdentifier&quot; width=&quot;1648&quot; height=&quot;730&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Ad frameworks has a shared instance, available within the whole system, in the form of a class named &lt;code&gt;ASIdentifierManager&lt;/code&gt;. We can ask for the shared instance as usual with the classical approach:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;ASIdentifierManager.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;shared&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Furthemore, we can ask for the current anonymous identifier as easy as:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;ASIdentifierManager.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;shared&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.advertisingIdentifier&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Before iOS14.5 you &lt;strong&gt;(the developer)&lt;/strong&gt; was &lt;em&gt;&lt;strong&gt;always&lt;/strong&gt;&lt;/em&gt; granted to get the above identifier in the form of an UUID object. This identifier is anonymous and consistent across all the operating system allowing to track users across different apps and domains. This, obviously, could lead to a lack of privacy if one or more players in this game are malicious (and, believe me, there’re tons of malicious players all the way around).&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/app-asking-for-identifier-480.avif 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/app-asking-for-identifier-960.avif 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/app-asking-for-identifier-1600.avif 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/app-asking-for-identifier-480.webp 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/app-asking-for-identifier-960.webp 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/app-asking-for-identifier-1600.webp 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/app-asking-for-identifier.png&quot; alt=&quot;Diagram: ASIdentifierManager.advertisingIdentifier in the center, shared with nine different apps shown as colored squares&quot; width=&quot;1876&quot; height=&quot;1434&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Since iOS14.5 you need to ask &lt;em&gt;&lt;strong&gt;app based&lt;/strong&gt;&lt;/em&gt; user consensus before you can access the above identifier. This means that you &lt;em&gt;&lt;strong&gt;(the user)&lt;/strong&gt;&lt;/em&gt; can decide who can access your identifier at every moment either when you install the app or - if you change your mind - from the Settings. That’s awesome in terms of user rights! And it's not opinable at all.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/att-tracking-settings-480.avif 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/att-tracking-settings-960.avif 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/att-tracking-settings-1125.avif 1125w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/att-tracking-settings-480.webp 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/att-tracking-settings-960.webp 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/att-tracking-settings-1125.webp 1125w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/att-tracking-settings.png&quot; alt=&quot;iOS Settings, Privacy, Tracking: the switch Allow Apps to Request to Track and a switch for the app AskPermissions, both on&quot; width=&quot;1125&quot; height=&quot;815&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Our goals for today is to wrap the above classes into a more convenient object that we could use both with Swift and SwiftUI. To achieve that we will use some basic Combine capabilities in order to expose correctly all pieces that we need.&lt;/p&gt;
&lt;p&gt;For such of conciseness we will use a pure SwiftUI approach, but all the relevant code will be also ready for Swift standard projects as well. Let’s start and create a SwiftUI project.&lt;/p&gt;
&lt;p&gt;The first thing to do is to add the relevant description within our &lt;strong&gt;Info.plist&lt;/strong&gt; in order to populate correctly the message that will appear to our users. Pretty much as with CoreLocation or Photos, we need to describe with an effective sentence what and why we need user consensus to track. To do that, we need to add a new key &lt;code&gt;NSUserTrackingUsageDescription&lt;/code&gt; and a paired phrase String as well.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attracking-infoplist-480.avif 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attracking-infoplist-960.avif 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attracking-infoplist-1048.avif 1048w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attracking-infoplist-480.webp 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attracking-infoplist-960.webp 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attracking-infoplist-1048.webp 1048w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attracking-infoplist.png&quot; alt=&quot;Info.plist source showing the NSUserTrackingUsageDescription key with the string I would like to track you for this reason.&quot; width=&quot;1048&quot; height=&quot;204&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Once we’re ready, we can start coding our helper class that will expose the relevant accessors to our App. We named this helper &lt;code&gt;ATTrackingHelper&lt;/code&gt;. Since we want to be &lt;strong&gt;notified&lt;/strong&gt; each time there’s a change either into &lt;code&gt;AuthorizationStatus&lt;/code&gt; or &lt;code&gt;AdvertisingIdentifier&lt;/code&gt;, we inherits from &lt;code&gt;ObservableObject&lt;/code&gt; and mark the two relevant properties as &lt;code&gt;@Published&lt;/code&gt;. This means that &lt;strong&gt;Combine&lt;/strong&gt;, under the hood, will create for us all the relevant code in order to track and notify subscribers whenever there is a change.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackinghelper-diagram-480.avif 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackinghelper-diagram-960.avif 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackinghelper-diagram-1600.avif 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackinghelper-diagram-480.webp 480w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackinghelper-diagram-960.webp 960w, https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackinghelper-diagram-1600.webp 1600w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/app-tracking-transparency-combine/attrackinghelper-diagram.png&quot; alt=&quot;Diagram of ATTrackingHelper: AuthorizationStatus and advertisingIdentifier marked @Published, a requestAuth() method between them, on top of ATTrackingManager and ASIdentifierManager&quot; width=&quot;1876&quot; height=&quot;1130&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;The last missing piece in order to make this class useful for our purpose is to expose a &lt;code&gt;requestAuth()&lt;/code&gt; method. The latter will interact with the framework and will populate the results accordingly.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ATTrackingHelper&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ObservableObject &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @Published&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ATTrackingManager.trackingAuthorizationStatus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @Published&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; currentUUID &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ASIdentifierManager.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;shared&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.advertisingIdentifier&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; requestAuth&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        guard&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ATTrackingManager.trackingAuthorizationStatus &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .authorized &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        ATTrackingManager.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;requestTrackingAuthorization&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            DispatchQueue.main.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;unowned&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self] &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                self.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .authorized {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    self.currentUUID &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ASIdentifierManager.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;shared&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.advertisingIdentifier&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Time for a Proof-Of-Concept. Given the above approach it will be as easy as declaring an ObservedObject within our ContentView. Pretty much like that:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @ObservedObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; trackingHelper &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ATTrackingHelper&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Your advertising ID:&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.callout&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;\(trackingHelper.currentUUID.uuidString)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.caption&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Spacer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Button&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    trackingHelper.requestAuth&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                }, label&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Ask for tracking&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Spacer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.vertical&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now we can ask for user consensus, first time we will run our app and populate the required uuidString. What a great time to be an iOS developer! :-)&lt;/p&gt;
&lt;p&gt;—
Happy coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI within UIKit: Connecting two worlds</title>
    <link href="https://www.sofapps.it/blog/swiftui-within-uikit/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swiftui-within-uikit/</id>
    <published>2021-03-24T00:00:00Z</published>
    <updated>2021-03-24T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Swift"/>
    <category term="Tutorial"/>
    <summary>A proof of concept born from a Clubhouse chat: instead of migrating a whole project, only the content of a UITableViewCell is rewritten in SwiftUI and hosted in a UIHostingController. UIKit talks to the SwiftUI view through NotificationCenter and Combine, and scrolling stays smooth. The approach is admittedly hackish, and the full code is on GitHub.</summary>
    <content type="html">&lt;p&gt;Last evening, I was involved in a very interesting Clubhouse room, talking about SwiftUI and Swift interoperability. The rest of the article is a proof-of-concept exploring some interesting ideas arisen with
Dimitri Giani, Stefano Mondino and Andrea Mengoli, during the chat.&lt;/p&gt;
&lt;p&gt;SwiftUI comes with both interesting performances and facilities in creating even complex layout but moving a complete project from Swift to SwiftUI couldn’t be always feasible for a lot of reasons (framework maturity, time constraints, etc.). So, why don’t take the best from the two worlds?&lt;/p&gt;
&lt;p&gt;There’re tons of &lt;a href=&quot;https://www.swiftbysundell.com/articles/swiftui-and-uikit-interoperability-part-2/&quot;&gt;tutorials&lt;/a&gt; and &lt;a href=&quot;https://www.avanderlee.com/swiftui/integrating-swiftui-with-uikit/&quot;&gt;articles&lt;/a&gt; related to the use of &lt;strong&gt;UIHostingController&lt;/strong&gt; that, as of today, seems to be the only viable solution to make the above propositions coming to light. However, last night we focused on a slightly different point-of-view:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Moving only very small portions of code from Swift to SwiftUI.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For example, one of the most hated things that every iOS developer would like to skip is dealing with Storyboard for &lt;strong&gt;UITableView/UICollectionView&lt;/strong&gt; cell design.&lt;/p&gt;
&lt;p&gt;Wouldn’t be nice to migrate just the content of such UITableViewCell to SwiftUI for performance, maintanability and easiness purpouses, making also future-proof at least some portion of our code? That was the
Dimitri Giani proposition.&lt;/p&gt;
&lt;p&gt;Everyone, including me, was sceptical since the use of UIHostingController seems a really complicated over-engineered approach for such performance-critical task (aka UIScrollView reusable components).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Needless to say, I was wrong. At least, in a very early test discussed in the rest of this article, this approach — with some caveats — works like a charm, without any performance issue.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot1-480.avif 480w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot1-960.avif 960w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot1-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot1-480.webp 480w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot1-960.webp 960w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot1-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot1.jpg&quot; alt=&quot;Storyboard sketch: a table view with an empty prototype cell, and a hand drawn SwiftUI view annotated as the rootView of a UIHostingController&quot; width=&quot;1400&quot; height=&quot;899&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Above, there is a draft of what we would like to achieve. As you can see, the UITableViewCell needs to be aware of the corresponding UIHostingController &lt;strong&gt;rootView&lt;/strong&gt; property and, since each UITableViewCell instance needs to be reusable we should keep those property unique.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot2-480.avif 480w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot2-960.avif 960w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot2-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot2-480.webp 480w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot2-960.webp 960w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot2-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot2.png&quot; alt=&quot;Code of CustomTableViewCell: it creates a UIHostingController, pins its view to the contentView in awakeFromNib and posts a notification in configure&quot; width=&quot;1400&quot; height=&quot;765&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;We make our CustomTableViewCell aware of that, by creating a private constant that instantiate a &lt;strong&gt;UIHostingController&lt;/strong&gt; and configure that object in the very early &lt;strong&gt;awakeFromNib&lt;/strong&gt; stage.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;configure(title:sfIcon:)&lt;/em&gt; method is just a placeholder that exploit the &lt;strong&gt;Combine&lt;/strong&gt; / &lt;strong&gt;publisher&lt;/strong&gt; approach in order to communicate with the corresponding &lt;strong&gt;SwiftUI&lt;/strong&gt; view. Here, we send a plain Notification when we need to configure the corresponding SwiftUIView.&lt;/p&gt;
&lt;p&gt;Please note, that we need to specify the &lt;strong&gt;object&lt;/strong&gt; property, since, we would like to deal &lt;em&gt;just&lt;/em&gt; with one instance of the object.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yep!, I’ve to admit, this looks really hackish…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot3-480.avif 480w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot3-960.avif 960w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot3-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot3-480.webp 480w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot3-960.webp 960w, https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot3-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-within-uikit/swiftui-with-uikit-shot3.png&quot; alt=&quot;Code of GuestView, a SwiftUI HStack with an image and a title that updates on a NotificationCenter publisher and conforms to Equatable&quot; width=&quot;1400&quot; height=&quot;1040&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;The SwiftUI counterpart is really simple. Here we create just an HStack container, in order to old both thumb image and title. We, also, adjust the frame in order to get all the space available without further constraints (the corresponding UIView that hold us will be responsible for the container dimension, ndr.). &lt;strong&gt;onReceive&lt;/strong&gt; we will update our corresponding states, making the view update itself where required.&lt;/p&gt;
&lt;p&gt;You’ll notice that I made the struct itself conform to Equatable, by adding both an &lt;em&gt;id&lt;/em&gt; and the relevant override method. This’s required in order to distinguish if we need to discard or take into account the received published method coming from &lt;strong&gt;NotificationCenter&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That’s all. Even if the above solution is a really hackish / over-engineered cell architecture, I’m really impressed by results: scrolling is smooth and without any glitch.&lt;/p&gt;
&lt;p&gt;I’m pretty sure that there should be other ways to achieve the same result with less boilerplate and/or in a much more elegant way (especially for the UIKit to SwiftUI communication).&lt;/p&gt;
&lt;p&gt;I can not wait to see your comments / commits. The full code is &lt;a href=&quot;https://github.com/valvoline/UIHostingTableViewTest&quot;&gt;available here&lt;/a&gt; on GITHUB.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Apple Silicon: Back to the future</title>
    <link href="https://www.sofapps.it/blog/apple-silicon-back-to-the-future/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/apple-silicon-back-to-the-future/</id>
    <published>2020-11-20T00:00:00Z</published>
    <updated>2020-11-20T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="Editorial"/>
    <summary>The post compares the introduction of the M1 to the iPhone in 2007, when Blackberry was suddenly displaced. Apple controls both hardware and software, while Dell, HP and Lenovo depend on Intel, and its technological lead is estimated at about six years. The author argues that neither an industry alliance nor waiting for Intel can close the gap quickly, because of time.</summary>
    <content type="html">&lt;p&gt;Year 2020 is gonna be remembered as a milestone for information technology, pretty much as 2007 was a milestone for mobile telephony.&lt;/p&gt;
&lt;p&gt;Tim Cook’s Apple has succeeded, once again, marking an historical step forward in the world of computing. I don’t think I’m exaggerating comparing the M1 introduction to the iPhone historical presentation that everyone here surely remember.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Certainly, times and actors are much different but the final result (and execution) is blowing away, the same way.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Intel will have to rearrange many of its (prehistorical) timelines in order to try to close the gap. Still, a comparison to 2007 comes naturally to me, like when Blackberry was suddenly ousted from the podium in a sudden and almost unexpected way — only for them, who did not want to see beyond their nose. Today’s Intel has an awkward production pipeline able to create just foot warmers; I don’t want to appear biased or whatever, but this is pretty much resembling reality of things, by now.&lt;/p&gt;
&lt;p&gt;Real problem is that in computers world things are far more complex compared to what happened for mobile phones in 2007. Computers are different beasts with a well established workflow and culture composed by a lot of tiny third parties components: Intel doesn’t produce final computers directly but only a small amount of those final products. And it’s not a case.&lt;/p&gt;
&lt;p&gt;Apple, on the other hand, since the very beginning has opted all-in to a seamlessly full integration among hardware and software. Stop reading and think for a moment:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What about if, when everything started, Wozniak had financial availabilities (such as the nowadays multimillionaire Apple) to build its own processor?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At the time things were completely different and Motorola was the closer partner in the quest to defeat a common enemy. Fortunately for them, times are changed and today’s Apple doesn’t seems to be interested in “sharing” its technological advantage (estimated in at least 6 years) with the world. Worth to note that six years are almost an era in computer field.&lt;/p&gt;
&lt;p&gt;Dell, Hp, Lenovo and all the other players has little to do other than try to bridge the gap starting to run the race. There are just two alternatives, imho:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Establish an alliance (as it was for USB) and try to build a processor as similar as possible to the Apple’s M1.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2)Stay on the Intel boat, hoping that the latter will give a radical change to its asset and something will change as soon as possible.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Both solutions are doomed to fail for the same simple reason: time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Whatever choice competitors take, it will take time and if it’s true, as rumors suggest, that Apple has been working on M1 for over eight years, this gives a clear idea of ​​how long it takes to catch up the winner.&lt;/p&gt;
&lt;p&gt;In the meantime Apple will rise, once again, the “best-selling computer” podium as it was in the first half of 2000 and - hopefully for them - the virtuous lock in / loop that binds Apple ecosystem will be secured for the next decade, at least.&lt;/p&gt;
&lt;p&gt;Steve Jobs could not have been prouder of his successor.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI Programming: ObjectBinding and BindableObject</title>
    <link href="https://www.sofapps.it/blog/swiftui-programming-objectbinding/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swiftui-programming-objectbinding/</id>
    <published>2020-01-10T00:00:00Z</published>
    <updated>2020-01-10T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Tutorial"/>
    <summary>@State fits value types owned by one View. For a class shared across views, SwiftUI offers @ObjectBinding together with the BindableObject protocol, which publishes changes through a Combine PassthroughSubject. A single instance then acts as the source of truth and every View refers to it by reference.</summary>
    <content type="html">&lt;p&gt;In a &lt;a href=&quot;https://www.sofapps.it/blog/swiftui-programming-states/&quot;&gt;previous article&lt;/a&gt; we have seen that in &lt;strong&gt;SwiftUI&lt;/strong&gt; is possible to associate one or more states to a View through the modifier &lt;strong&gt;@State&lt;/strong&gt;; the latter must be used with &lt;em&gt;&lt;strong&gt;value types&lt;/strong&gt;&lt;/em&gt; allocated within the declaring View. This way our application is able to autonomously understand when to update the user interface with respect to the changes made to our variable marked with @State which, we recall, is identified as a &lt;strong&gt;source of truth&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But what if our &lt;strong&gt;source of truth&lt;/strong&gt; is a &lt;em&gt;&lt;strong&gt;complex object&lt;/strong&gt;&lt;/em&gt; designed, for example, as a class construct? In this case @State will fail in its intent because it is designed to work exclusively with local properties of our View.&lt;/p&gt;
&lt;p&gt;SwiftUI provides a better further concept to dialogue with that case: &lt;strong&gt;@ObjectBinding&lt;/strong&gt;. The latter could be used in all cases in which the property is passed by reference such as in the class case.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; MyCustomObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @ObjectBinding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; myObject&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;myObject.someTextProperty&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;bindableobject-protocol&quot;&gt;BindableObject protocol&lt;/h2&gt;
&lt;p&gt;Properties with an associated &lt;strong&gt;@ObjectBinding&lt;/strong&gt; modifier, therefore, refer to class objects. In order for a class to be compatible with the @ObjectBinding modifier, the &lt;strong&gt;BindableObject&lt;/strong&gt; protocol must be adopted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BindableObject&lt;/strong&gt; protocol is fairly simple in its simpliest variant and requires only that our class implement a property called didChange, which will notify the subscribed View objects so that they can react correctly to visual interface changes.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; MyObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; BindableObject &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; didChange &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; PassthroughSubject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Never&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; someTextProperty:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        didSet&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            didChange.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;combine-framework-and-passthroughsubject&quot;&gt;Combine framework and PassthroughSubject&lt;/h2&gt;
&lt;p&gt;In order to work, the code above needs to include the support for the Combine framework at the beginning of our swift file.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Combine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Combine framework&lt;/strong&gt; is a very powerful and somewhat complex tool that we will see in a future article. For now we just need to know that it &lt;em&gt;- among many other things -&lt;/em&gt; provides a class called &lt;strong&gt;PassthroughSubject&lt;/strong&gt; (our property didChange is an instance of this class). It is responsible to notify (Publishing) the interested parties (Subscribers) that a specific event happened.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PassthroughSubject&lt;/strong&gt;, as the name suggests, behaves very similarly to traditional notifications made available by the Swift Foundation framework with NSNotificationCenter: the object specified as a parameter (in our case Void, since we don't want to pass any parameter) is passed roughly and without any modification to the recipient along with a &lt;em&gt;&lt;strong&gt;notification event&lt;/strong&gt;&lt;/em&gt; that trigger a new rebuild of the view.&lt;/p&gt;
&lt;p&gt;If you want to specify an error along with the notification, you can pass it as a second parameter. In our example we are not interested in this eventuality and it is the reason why we pass Never as the second parameter for the PasstroughSubject invocation.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; didChange &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; PassthroughSubject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Never&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Once an instance of type &lt;strong&gt;PassthroughSubject&lt;/strong&gt; is created, it could be used to perform the publishing of our event whenever we wish to &lt;em&gt;notify&lt;/em&gt; subscribed Views about changes in our &lt;strong&gt;source of truth&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To accomplish the last requirement we use the didSet construct made available by Swift which is invoked whenever the value of a propery changes:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; someTextProperty:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    didSet&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        didChange.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This way, when we make a change to the &lt;em&gt;someTextProperty&lt;/em&gt; the &lt;strong&gt;didSet construct&lt;/strong&gt; will be invoked. Inside it we will make a call to the send() method of the PassthroughSubject instance.Notice how we specify a Void type parameter by passing a pair of parentheses () within the method.&lt;/p&gt;
&lt;p&gt;Doing so all objects subscribed to changes - those that have declared their property as &lt;strong&gt;@ObjectBinding&lt;/strong&gt; -  will know that the time has come to refresh their body.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/objectbindingsimpleflowstateen-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/objectbindingsimpleflowstateen-669.avif 669w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/objectbindingsimpleflowstateen-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/objectbindingsimpleflowstateen-669.webp 669w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/objectbindingsimpleflowstateen.jpg&quot; alt=&quot;Simple schema illustrating references with ObjectBinding.&quot; width=&quot;669&quot; height=&quot;409&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.1 - Simple schema illustrating references with ObjectBinding.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;As you can see from the diagram above, our model is characterized by a &lt;strong&gt;single instance&lt;/strong&gt; in memory, through a class compliant with the &lt;strong&gt;BindableObject protocol&lt;/strong&gt;. Our View objects contain a &lt;em&gt;reference&lt;/em&gt; to the original object.&lt;/p&gt;
&lt;p&gt;This way a characteristic problem known as the &lt;em&gt;duplication&lt;/em&gt; of the source of truth is avoided: changes to the model will be unique and characterized by an immediate update of all the views that refer our class.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/sourceoftruthandobjectbinding-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/sourceoftruthandobjectbinding-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/sourceoftruthandobjectbinding-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/sourceoftruthandobjectbinding-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/sourceoftruthandobjectbinding-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/sourceoftruthandobjectbinding-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/sourceoftruthandobjectbinding.jpg&quot; alt=&quot;Simple schema illustrating source of truth and ObjectBinding.&quot; width=&quot;1000&quot; height=&quot;462&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.2 - Simple schema illustrating source of truth and ObjectBinding.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;an-example&quot;&gt;An example&lt;/h2&gt;
&lt;p&gt;Let's try to put the above concepts into practice with an example. In the previous article we had configured our CustomTableViewCell to use a variable passed by value containing a struct named Person.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CustomTableViewCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; model: Person&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This approach didn't allow the CustomTableViewCell to be independent regarding updates of its own content; The variable, in fact, was copied during the CustomTableViewCell init phase.&lt;/p&gt;
&lt;p&gt;Every change to its content was managed through a @State variable, owned by ContentView that regenerate the new cell with the new content each time a change happen.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/statevsobjectbindingreference-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/statevsobjectbindingreference-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/statevsobjectbindingreference-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/statevsobjectbindingreference-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/statevsobjectbindingreference-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-objectbinding/statevsobjectbindingreference-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-objectbinding/statevsobjectbindingreference.jpg&quot; alt=&quot;State vs Object binding reference.&quot; width=&quot;1000&quot; height=&quot;284&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.3 - State vs Object binding reference.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Through the use of the &lt;strong&gt;@ObjectBinding&lt;/strong&gt; concept, we can make unique the &lt;em&gt;Person model&lt;/em&gt; by passing just a reference to the CustomTableViewCell, as shown in the graph above on the right.&lt;/p&gt;
&lt;p&gt;The first thing to do is modify our Person model to use a class that &lt;em&gt;conforms&lt;/em&gt; to the &lt;strong&gt;BindableObject&lt;/strong&gt; protocol instead of a &lt;strong&gt;struct&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Person&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; BindableObject &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; didChange &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; PassthroughSubject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Never&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; photoName:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;didSet&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; } }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; title:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;didSet&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; } }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; subtitle:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;didSet&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; } }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    init&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        self.photoName &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; photoName&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        self.title &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; title&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        self.subtitle &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; subtitle&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; update&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        didChange.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Our new model &lt;em&gt;adopts&lt;/em&gt; the &lt;strong&gt;BindableObject&lt;/strong&gt; protocol by implementing the &lt;em&gt;+didChange&lt;/em&gt;* property through a &lt;strong&gt;PassthroughSubject&lt;/strong&gt; &lt;em&gt;instance&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Each property affected by possible changes to the visual interface ( photoName, title and subtitle ) has been adequately modified to react through the didSet construct. This way, whenever we update one of the variables, the update() function will be triggered by sending, in turn, a notification to all subscribers through the PassthroughSubject instance.&lt;/p&gt;
&lt;p&gt;Finally, CustomTableViewCell will be modified to take advantage of the new reference model. To do this we simply prepend the @ObjectBinding modifier discussed above.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CustomTableCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @ObjectBinding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; model: Person&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model.photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resizable&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aspectRatio&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;contentMode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .fit&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;clipShape&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Circle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;frame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .center&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model.subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Spacer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This way the CustomTableViewCell does not have a copy of the Person model. Instead it works with a reference to the memory area in which the original model is stored. Let's see where and how to create the model to be passed as a reference.&lt;/p&gt;
&lt;p&gt;ContentView will be responsible for such requirement, creating the actual model in memory and by passing it by reference to the CustomTableViewCell.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; dataSource:[Person] &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        Person&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Mario Rossi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Amministratore&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        Person&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Giuseppe Bianchi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Consigliere&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        Person&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Luca Verdi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Funzionario&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            CustomTableCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            CustomTableCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            CustomTableCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;list-and-tableview&quot;&gt;List and TableView&lt;/h2&gt;
&lt;p&gt;This new version of ContentView uses a new object called List which groups elements pretty much the VStack counterpart. The difference is in the visualization: the result will be much like an UITableView from the counterpart UIKit framework&lt;/p&gt;
&lt;p&gt;What we see above is List simplest form of declaration. In the next article we will see how to make its content dynamic, based on the declared model.&lt;/p&gt;
&lt;p&gt;--See you soon!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI Programming: An Introduction to States</title>
    <link href="https://www.sofapps.it/blog/swiftui-programming-states/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swiftui-programming-states/</id>
    <published>2020-01-09T00:00:00Z</published>
    <updated>2020-01-09T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Tutorial"/>
    <summary>In SwiftUI a view is an immutable struct, and @State lets the framework allocate a variable outside it and redraw the body whenever the value changes. This avoids the scattered state and threading issues of a UIKit view controller. The post also extracts a subview, passes parameters and a model to it, and shows that @State does not react to changes inside a class.</summary>
    <content type="html">&lt;p&gt;We have seen in &lt;a href=&quot;https://www.sofapps.it/blog/swiftui-programming-classes-structs/&quot;&gt;a previous article&lt;/a&gt; that in SwiftUI a View is a struct that &lt;em&gt;conforms&lt;/em&gt; to the &lt;em&gt;View protocol&lt;/em&gt;. Therefore, it does not inherit any stored property just because there is no father at all; it is allocated on the stack and its operated by value and not by reference (as is the case with classes in UIKit).&lt;/p&gt;
&lt;h2 id=&quot;how-views-works-in-swiftui&quot;&gt;How views works in SwiftUI&lt;/h2&gt;
&lt;p&gt;Behind the scenes, &lt;strong&gt;SwiftUI&lt;/strong&gt; manages the Views with the help of an highly efficient data structure for on-screen rendering of the content. For this reason it is advisable to use and create &lt;strong&gt;specialized&lt;/strong&gt; and &lt;strong&gt;reusable&lt;/strong&gt; components. During development - Cupertino reassures - you should not have hesitations to extract views that perform a specific task and create for them a specific View object.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;Together with the body, a View in SwiftUI defines its dependencies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Let suppose we want to create a View in SwiftUI specialized in creating and handling a button. Simply, our object will have to take charge of managing a single scope: at its pressure, the label will have to change reflecting the new state.&lt;/p&gt;
&lt;p&gt;That last point is where the declarative programming shines: &lt;em&gt;&lt;strong&gt;the consequence of an action as a way to update the interface&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-state-attribute-in-swiftui&quot;&gt;The @State attribute in SwiftUI&lt;/h2&gt;
&lt;p&gt;Our button, therefore, will have a dependency between its state and its representation on the screen. In SwiftUI this dependency is automatically managed by the new @State modifier. Let's try an example to better understand this concept.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; MyButton&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @State&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; toggleStatus:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        Button&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            self.toggleStatus &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;self.toggleStatus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;(toggleStatus &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Press Me&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Unpress me&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;@State&lt;/strong&gt; binds the toggleStatus variable to the interface concept: whenever its value changes, SwiftUI will know that it is necessary to generate a new body (and therefore a refresh of the label associated with it).&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/swiftuiviewdataflow-391.avif 391w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/swiftuiviewdataflow-391.webp 391w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/swiftuiviewdataflow.jpg&quot; alt=&quot;Simple diagram illustrating the data flow related to the code above.&quot; width=&quot;391&quot; height=&quot;94&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.1 - Simple diagram illustrating the data flow related to the code above.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;try-removing-state-from-the-code-above-what-happens-and-why&quot;&gt;Try removing @State from the code above. What happens and why?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Removing the @State attribute, the compiler will complain that we are trying to change an immutable value: don't forget that we are in the presence of a struct.
Every object that is rendered on the screen, in fact, is immutable for performance reasons. This way, SwiftUI knows what needs to be updated and what can be left out
By adding a @State modifier, we are explicitly telling SwiftUI:&lt;/p&gt;
&lt;p&gt;&amp;quot;Beware! There's an object here that could change its state, so you'll need to update its contents.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Therefore, SwiftUI implicitly defines a dependency between this variable and the View on-screen presentation each time it will encounter a @State attribute. That way, whenever the variable changes value, SwiftUI will know that the View must be redrawn using the new value.&lt;/p&gt;
&lt;p&gt;To seal this concept and see how much different it is from traditional programming, let's try to make a joint with UIKit:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIKit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ViewController&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIViewController &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	@IBOulet&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aButton: UIButton&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; toggleStatus:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;	&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	override&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; viewDidLoad&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;		super.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;viewDidLoad&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	@IBAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; buttonDidPressed&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;sender&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UIButton) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;		sender.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;setTitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;(toggleStatus) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Unpress me&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Press me&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .normal&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;		toggleStatus &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;toggleStatus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Clearly in &lt;strong&gt;UIKit&lt;/strong&gt;, the code above is not enough to render a working screen application. We will have to create a &lt;strong&gt;Storyboard&lt;/strong&gt; with a UIViewController and an UIButton. We will, also, have to align the button with &lt;strong&gt;Constraints&lt;/strong&gt; in the center and create the correct &lt;strong&gt;@IBOutlet&lt;/strong&gt; and &lt;strong&gt;@IBAction&lt;/strong&gt; references to make the whole flow working.&lt;/p&gt;
&lt;p&gt;Leaving aside the obvious greater amount of code and actions compared to SwiftUI, let's focus on our &lt;strong&gt;state&lt;/strong&gt;. Also in this case, in fact, our button needs to discern the current state in order to be able to change its representation (label). Notice how, in the case of traditional imperative programming, there are two major conceptual concerns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;toggleStatus&lt;/strong&gt; is managed (allocated, initialized and modified) by the Controller.&lt;/li&gt;
&lt;li&gt;There is no clear code-level way to separate variables related to the state of the interface from traditional ones: they are all the same!&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/viewcontrollerstatusdataflow-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-states/viewcontrollerstatusdataflow-530.avif 530w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/viewcontrollerstatusdataflow-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-states/viewcontrollerstatusdataflow-530.webp 530w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/viewcontrollerstatusdataflow.jpg&quot; alt=&quot;A diagram illustrating the relationships and flow of our Button object in UIKit.&quot; width=&quot;530&quot; height=&quot;217&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.2 - A diagram illustrating the relationships and flow of our Button object in UIKit.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It is also evident how the complexity of this approach grows exponentially with the increasing number of objects and states.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/interfacecomplexityvsstate-en-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-states/interfacecomplexityvsstate-en-646.avif 646w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/interfacecomplexityvsstate-en-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-states/interfacecomplexityvsstate-en-646.webp 646w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/interfacecomplexityvsstate-en.jpg&quot; alt=&quot;Diagram illustrating the increase in complexity as the states managed by the interface grow.&quot; width=&quot;646&quot; height=&quot;383&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.3 - Diagram illustrating the increase in complexity as the states managed by the interface grow.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;There's one more thing we should underline there: iOS is a &lt;em&gt;&lt;strong&gt;multithreaded&lt;/strong&gt;&lt;/em&gt; operating system. This means that requests for status and interface updates can come from multiple points in the code and that threads work independently from each other. Without a clear way to handle such kind of circumstances lead to inconsistences in the UI and therefore a bugs that are hard to discover and fix.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/uiviewcontrollermultithreaddataflow-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-states/uiviewcontrollermultithreaddataflow-848.avif 848w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/uiviewcontrollermultithreaddataflow-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-states/uiviewcontrollermultithreaddataflow-848.webp 848w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/uiviewcontrollermultithreaddataflow.jpg&quot; alt=&quot;In the case of a multithreaded application boundary between who updates the interface and who updates the status is not clear.&quot; width=&quot;848&quot; height=&quot;301&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.4 - In the case of a multithreaded application boundary between who updates the interface and who updates the status is not clear.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;the-search-for-truth&quot;&gt;The search for truth&lt;/h2&gt;
&lt;p&gt;But how is managed this dependency between variables and interface in SwiftUI? And what makes the system resilient and scalable unlike a traditional imperative approach?&lt;/p&gt;
&lt;p&gt;When SwiftUI processes a View with a variable of type @State, it allocates a space for this variable in memory on behalf of the View.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/stateallocationinswiftuien-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-states/stateallocationinswiftuien-489.avif 489w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/stateallocationinswiftuien-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-states/stateallocationinswiftuien-489.webp 489w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/stateallocationinswiftuien.jpg&quot; alt=&quot;@State variable allocation in SwiftUI.&quot; width=&quot;489&quot; height=&quot;268&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.5 - @State variable allocation in SwiftUI.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;By adding the &lt;strong&gt;@State&lt;/strong&gt; attribute, we are able to modify an object that is &lt;em&gt;&lt;strong&gt;otherwise immutable&lt;/strong&gt;&lt;/em&gt; as a struct: behind the scenes, in fact, the variable is allocated by the SwiftUI framework in a read/write area of the application.&lt;/p&gt;
&lt;p&gt;In SwiftUI, every possible View state (scrollview offset, button status, stack contets, etc.) is managed by this concept otherwise known as &lt;strong&gt;Source of Truth&lt;/strong&gt;. Following this concept, it is possible to classify each variable either as a &lt;em&gt;&lt;strong&gt;source of truth&lt;/strong&gt;&lt;/em&gt; or a &lt;em&gt;&lt;strong&gt;derived value&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/sourceoftruthtableen-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-states/sourceoftruthtableen-895.avif 895w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/sourceoftruthtableen-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-states/sourceoftruthtableen-895.webp 895w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/sourceoftruthtableen.jpg&quot; alt=&quot;Diagram showing classifications of variables in SwiftUI.&quot; width=&quot;895&quot; height=&quot;419&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.6 - Diagram showing classifications of variables in SwiftUI.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;In our example above, &lt;strong&gt;toggleStatus&lt;/strong&gt; is a &lt;strong&gt;source of truth&lt;/strong&gt;. Moreover, from the diagram above, we could argue that all &lt;strong&gt;constants&lt;/strong&gt; are also a source of truth while a simple property is a derived one.&lt;/p&gt;
&lt;p&gt;We will see in the next chapters that there is another mechanism for passing derived read/write values, called &lt;strong&gt;@Binding&lt;/strong&gt;. We will focus also in what a a derived value differs from the corresponding source of truth with a practical example. We will analyze the differences with &lt;strong&gt;@State&lt;/strong&gt; and how and when to use one with respect to the other.&lt;/p&gt;
&lt;h2 id=&quot;organize-the-code-view-extraction&quot;&gt;Organize the code: view extraction&lt;/h2&gt;
&lt;p&gt;Now that we have clear how a View updates and rebuild its content, let's try to put together what we learned in relation to the example of the last article. Last time, we left our ContentView as follow:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SwiftUI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resizable&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aspectRatio&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;contentMode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .fit&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;clipShape&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Circle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;frame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .center&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Mario Rossi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Amministratore delegato&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Spacer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Clearly this approach is not maintainable. The code has a tendency to nest and growing towards the right, in a so-called &lt;a href=&quot;https://itnext.io/pyramid-of-doom-the-signs-and-symptoms-of-a-common-anti-pattern-c716838e1819&quot;&gt; &amp;quot;doom pyramid&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At the beginning of the article, we mentioned a mechanism for extracting subviews in order to make the code scalable and maintainable. Let's see what the new Xcode11 and SwiftUI environment offer us to solve this problem.&lt;/p&gt;
&lt;p&gt;Be sure to be using Xcode11 and move the mouse to the HStack tag. Holding down the CMD (⌘) state click on the tag, as follow:&lt;/p&gt;
&lt;figure class=&quot;figure-grid&quot;&gt;&lt;div&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep1-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep1-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep1-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep1-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep1-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep1-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep1.jpg&quot; alt=&quot;Xcode automatically creates a new struct giving us the possibility to change the name.&quot; width=&quot;1000&quot; height=&quot;784&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep2-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep2-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep2-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep2-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep2-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep2-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/extractsubviewstep2.jpg&quot; alt=&quot;Xcode automatically creates a new struct giving us the possibility to change the name.&quot; width=&quot;1000&quot; height=&quot;883&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/div&gt;&lt;figcaption&gt;Fig.7 - Xcode automatically creates a new struct giving us the possibility to change the name.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Xcode automatically creates a new struct, extracts the selected content and uses it to populate the body of the newly generated object. At the end of the operation, it also offers us the possibility of changing the name: rename the View extracted in &lt;strong&gt;CustomTableViewCell&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The new version of &lt;strong&gt;ContentView&lt;/strong&gt; has now become much more readable and lightweight, including only a reference to a new object. As a niccce to have, we could also move the contents of the &lt;strong&gt;CustomTableViewCell&lt;/strong&gt; into a new file to better isolate the concept of component.&lt;/p&gt;
&lt;h2 id=&quot;passing-parameters&quot;&gt;Passing parameters&lt;/h2&gt;
&lt;p&gt;Wouldn't it be interesting to pass the right parameters to our new CustomTableViewCell, in order to generate a cell with dynamic contents such as title, subtitle and image? Let's try to modify our new class to get this result:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CustomTableCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; photoName:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; title:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; subtitle:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resizable&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aspectRatio&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;contentMode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .fit&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;clipShape&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Circle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;frame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .center&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Spacer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, inside the &lt;strong&gt;ContentView&lt;/strong&gt;, our &lt;strong&gt;CustomTableCell&lt;/strong&gt; can be created with parameters that uniquely define its content.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            CustomTableCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Gianluca Verdi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                             subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Consigliere&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;What if we would like to go further and create, for example, a button that changes the contents of the subtitle field?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-model-the-object-and-swiftui&quot;&gt;The model, the object and SwiftUI&lt;/h2&gt;
&lt;p&gt;The model linked to a View object plays a fundamental role in SwiftUI's declarative paradigm. Each object typically has a model associated with it that, together with the state, completely identifies the user interface displayed.&lt;/p&gt;
&lt;p&gt;For example, we could associate a model of this type with our &lt;strong&gt;CustomTableViewCell&lt;/strong&gt;:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Person&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; photoName:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; title:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; subtitle:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;As a result, our View will have to be changed in order to take advantage of the new model just created:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CustomTableViewCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; model: Person&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model.photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resizable&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aspectRatio&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;contentMode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .fit&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;clipShape&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Circle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;frame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .center&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model.subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Spacer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Finally, the &lt;strong&gt;ContentView&lt;/strong&gt; must reflect this change to properly render on screen our &lt;strong&gt;CustomTableViewCell&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @State&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; model &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Person&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;photoName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                               title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Mario Rossi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                            subtitle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Amministratore delegato&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            CustomTableViewCell&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; model&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Button&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                self.model.subtitle &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Consigliere&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Change subtitle&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;foregroundColor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Color.white&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;background&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Color.blue&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;cornerRadius&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This time the model variable has the attribute &lt;strong&gt;@State&lt;/strong&gt;: The model owner is the &lt;strong&gt;ContentView&lt;/strong&gt; object, it is then passed by copy &lt;em&gt;&lt;strong&gt;- let us remember that we are working with structures and not with classes -&lt;/strong&gt;&lt;/em&gt; to the &lt;strong&gt;CustomTableViewCell&lt;/strong&gt; which, in turn, uses it to render the corresponding fields of its objects: Image and Text.&lt;/p&gt;
&lt;p&gt;The button has an action to update the model that changes its subtitle. Since ContentView has added the &lt;strong&gt;@State&lt;/strong&gt; attribute to its model, any change of the latter triggers the update of its body which, in turn, &lt;em&gt;regenerates&lt;/em&gt; a new CustomTableViewCell with the brand new content.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/dataflowpassingargs-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-states/dataflowpassingargs-610.avif 610w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-states/dataflowpassingargs-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-states/dataflowpassingargs-610.webp 610w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-states/dataflowpassingargs.jpg&quot; alt=&quot;Flow schema illustrating object status update.&quot; width=&quot;610&quot; height=&quot;280&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.8 - Flow schema illustrating object status update.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;You may have noticed that I added the &lt;strong&gt;private&lt;/strong&gt; attribute before declaring the model status variable. This is because, as we explained above, the variables marked as &lt;strong&gt;@State&lt;/strong&gt; belong exclusively to the View that declares them. It is therefore a good idea to reinforce this concept by marking them as private.&lt;/p&gt;
&lt;p&gt;We will see in the next article that &lt;strong&gt;SwiftUI&lt;/strong&gt; exposes other ways to manage parameters and injection when we are dealing with situations like the one illustrated above. In this case, in fact, although syntactically and functionally correct, our flow suffers from a small problem: our CustomTableViewCell uses its own copy of the model which in turn is exposed, allocated and managed by ContentView with a private variable.&lt;/p&gt;
&lt;p&gt;SwiftUI offers abstractions very similar to the @State attribute to handle these circumstances and allow the model to be propagated correctly where needed.&lt;/p&gt;
&lt;h3 id=&quot;what-happens-if-we-change-the-model-from-struct-to-class&quot;&gt;What happens if we change the model from struct to class?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Although the project will continue to compile and run without problems, unfortunately we will notice that in practice the button will no longer change the content of the subtitle field.&lt;/p&gt;
&lt;p&gt;@State works with value types, while classes are reference types: by changing the value of a class marked with the @State attribute, its internal change does not trigger the body update.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;-- 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI Programming: Building more complex views</title>
    <link href="https://www.sofapps.it/blog/swiftui-programming-complex-views/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swiftui-programming-complex-views/</id>
    <published>2020-01-08T00:00:00Z</published>
    <updated>2020-01-08T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Tutorial"/>
    <summary>Container views such as VStack build their content through a ViewBuilder closure, which replaces addSubview and Auto Layout constraints with declarative composition. The post builds a title and subtitle row with a circular image using stacks, modifiers and Spacer. It also notes that if let is not accepted inside a ViewBuilder.</summary>
    <content type="html">&lt;p&gt;We have seen that SwiftUI always requires to expose a &lt;strong&gt;body&lt;/strong&gt; that returns a View. In the construction of complex views, however, it is necessary to compose these Views with a &lt;strong&gt;specific layout&lt;/strong&gt; and return them in the form of a &lt;strong&gt;single object&lt;/strong&gt;. To do this, SwiftUI comes to our aid through the &lt;em&gt;Content View&lt;/em&gt; concept.&lt;/p&gt;
&lt;p&gt;The basic objects with which we talk, such as Text that we saw in the previous chapter, &lt;em&gt;adhere&lt;/em&gt; to the &lt;strong&gt;View protocol&lt;/strong&gt;. There are other, more complex objects, that in the declaration of their API have a format similar to the following:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; where&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Content &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The above is the declaration of the &lt;strong&gt;VStack&lt;/strong&gt; component that we will analyze during the rest of the article. If we look at the definition of Content, we will see that:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;@_functionBuilder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ViewBuilder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; buildBlock&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: Content) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Content &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Content &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Basically, objects like &lt;strong&gt;VStack&lt;/strong&gt; use a &lt;strong&gt;ViewBuilder&lt;/strong&gt; constructor to compose multiple View types together.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-viewbuilder-closure&quot;&gt;The ViewBuilder closure&lt;/h2&gt;
&lt;p&gt;The closure viewbuilder allows us to insert typically declarative instructions inside it: instead of invoking an &lt;strong&gt;addSubview&lt;/strong&gt; method, as we did with &lt;strong&gt;UIKit&lt;/strong&gt;, we will insert a list with all the views contained &lt;em&gt;&lt;strong&gt;directly&lt;/strong&gt;&lt;/em&gt; within the closure.&lt;/p&gt;
&lt;p&gt;To better understand this concept, let's take a closer look at the definition for the VStack struct:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;Content&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; where&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Content &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: HorizontalAlignment &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .center, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        spacing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: Length&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        @&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;ViewBuilder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: () &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The content parameter is defined as a closure &lt;strong&gt;() -&amp;gt; Content&lt;/strong&gt;. The compiler knows this attribute implicitly marked as &lt;strong&gt;@ViewBuilder&lt;/strong&gt; and knows how to transform it into a new closure that returns a view representing all the content declared within &lt;strong&gt;VStack&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;This principle is present in all objects that expose a where Content: View clause&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;stack-view&quot;&gt;Stack View&lt;/h2&gt;
&lt;p&gt;A Stack View is a special View of kind Container View that allows us to return a composition of other View objects, according to a vertical, horizontal or depth layout.&lt;/p&gt;
&lt;p&gt;Continuing our comparisons with the &lt;strong&gt;UIKit&lt;/strong&gt; framework, the corresponding object that we will analyze in this paragraph, are the &lt;strong&gt;UIStackView&lt;/strong&gt;. In SwiftUI, however, apart from the basic concept there is very little of the classic UIStackView.&lt;/p&gt;
&lt;p&gt;Stacks objects currently available are of three flavours: &lt;strong&gt;HStack&lt;/strong&gt;, &lt;strong&gt;VStack&lt;/strong&gt; and &lt;strong&gt;ZStack&lt;/strong&gt;. Respectively: Horizontal Stack, Vertical Stack and Depth Stack (Z indicates the depth dimension).&lt;/p&gt;
&lt;p&gt;These objects together with the modifiers we saw in the previous chapter, allow us to &lt;em&gt;&lt;strong&gt;completely replace&lt;/strong&gt;&lt;/em&gt; the concept of Auto Layout and Constraints. From a technical point of view, this greatly increases the responsiveness and the rendering speed of the application, because the system does not need to pre-calculate any specific constraint or layout: everything is declared a priori, in a full declarative style.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/simpleinterfacehierarchytree-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/simpleinterfacehierarchytree-564.avif 564w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/simpleinterfacehierarchytree-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/simpleinterfacehierarchytree-564.webp 564w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/simpleinterfacehierarchytree.png&quot; alt=&quot;A simple hierarchy that show a typical VStack use.&quot; width=&quot;564&quot; height=&quot;681&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.1 - A simple hierarchy that show a typical VStack use.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;In code, we'll write something like this:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SwiftUI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;           Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;           Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;           Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;           Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;           Slider&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;As you can see, unlike UIKit, references to methods like addSubview are no longer present. In SwiftUI, views are created entirely with a process of declarative composition of the structures. Simply, let's say to the compiler that our ContentView has inside a VStack container with inside: Image, Text, Text, Text and Slider.&lt;/p&gt;
&lt;p&gt;We are not paying attention to individual factory methods for now. We will have time to return to slider images and advanced controls immediately ahead. For now, the important thing is to understand exactly what is happening and why.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A very important note relative to ViewBuilder regards the syntax to be used in it. Even if we are in the presence of Swift, in fact, within this closure it is not possible to use some typical operators to which we have been accustomed, such as the optional unwrapper:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anImage &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anImage {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;       Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Slider&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This code will produce a compilation error. The ViewBuilder closure cannot - for now - correctly parse the optional unwrapping concept. The following code, on the other hand, works correctly:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anImage &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;       Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Slider&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;build-a-custom-tableviewcell&quot;&gt;Build a custom TableViewCell&lt;/h2&gt;
&lt;p&gt;Since the easiest way to learn a new tool is to go to practice, in this section we will try to replicate the typical behavior of a UITableViewCell with title and subtitle. The result we would like to achieve is something like this:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/uitableviewcellmockup-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/uitableviewcellmockup-785.avif 785w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/uitableviewcellmockup-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/uitableviewcellmockup-785.webp 785w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/uitableviewcellmockup.png&quot; alt=&quot;TableViewCell that we would like to achieve.&quot; width=&quot;785&quot; height=&quot;214&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.2 - TableViewCell that we would like to achieve.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;First thing to do is to create a new project that includes support for SwiftUI:&lt;/p&gt;
&lt;figure class=&quot;figure-grid&quot;&gt;&lt;div&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject1-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject1-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject1-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject1-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject1-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject1-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject1.jpg&quot; alt=&quot;Steps to follow&quot; width=&quot;1000&quot; height=&quot;716&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject2-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject2-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject2-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject2-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject2-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject2-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newproject2.jpg&quot; alt=&quot;Steps to follow&quot; width=&quot;1000&quot; height=&quot;716&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/div&gt;&lt;figcaption&gt;Fig.3 - Steps to follow&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;We will now replace the &lt;strong&gt;ContentView&lt;/strong&gt; struct provided by default with the following code:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;		VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;			Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Mario Rossi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;			Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Amministratore delegato&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;		}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;At this point in the &lt;strong&gt;Preview Canvas&lt;/strong&gt; pane, you should see the result of your statements appear magically:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/firstpreview-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/firstpreview-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/firstpreview-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/firstpreview-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/firstpreview-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/firstpreview-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/firstpreview.jpg&quot; alt=&quot;Preview pane in Xcode11 showing the result of our declarations to the SwiftUI framework.&quot; width=&quot;1000&quot; height=&quot;575&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.4 - Preview pane in Xcode11 showing the result of our declarations to the SwiftUI framework.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;If you don't see anything, first make sure you're in a MacOS Catalina 10.15 environment, the Live Preview system, works exclusively on this environment. If you are already in 10.15 but you still don't see the live preview, make sure you have enabled the Canvas panel as follows:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/enablecanvas-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/enablecanvas-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/enablecanvas-986.avif 986w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/enablecanvas-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/enablecanvas-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/enablecanvas-986.webp 986w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/enablecanvas.png&quot; alt=&quot;To get the Live Preview working, be sure to be in Catalina 10.15 and have enabled the Canvas panel.&quot; width=&quot;986&quot; height=&quot;598&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.5 - To get the Live Preview working, be sure to be in Catalina 10.15 and have enabled the Canvas panel.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Simple? You bet! We still lack some elements to complete our work. The first thing is the image. Download the reference image that you find at the bottom of the article and, taking care to select the Assets.xcassets folder of your project, drag the image you have just downloaded into it.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/dragimageasset-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/dragimageasset-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/dragimageasset-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/dragimageasset-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/dragimageasset-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/dragimageasset-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/dragimageasset.jpg&quot; alt=&quot;Import an image for our assignment inside the assets folder.&quot; width=&quot;1000&quot; height=&quot;691&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.6 - Import an image for our assignment inside the assets folder.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;the-image-object&quot;&gt;The Image object&lt;/h2&gt;
&lt;p&gt;Every framework must have the possibility to dialogue in a more or less complete and complex way with images. &lt;strong&gt;SwiftUI&lt;/strong&gt; offers a truly formidable support for this type of objects that will not make us regret even its cousin &lt;strong&gt;UIImageView&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image&lt;/strong&gt; is a View object (the result is an object adhering to the View protocol). In its most basic form, we supply the name of an image to display:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The result is the a View with the image provided as an argument. If we try to insert this instruction inside the VStack:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Mario Rossi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Amministratore delegato&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;result will not be exactly what was hoped for:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/firstattemptimage-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/firstattemptimage-571.avif 571w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/firstattemptimage-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/firstattemptimage-571.webp 571w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/firstattemptimage.png&quot; alt=&quot;The first attempt with Image is not exactly what was hoped for!&quot; width=&quot;571&quot; height=&quot;1000&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.7 - The first attempt with Image is not exactly what was hoped for!&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Lets try to solve this problem. The first thing to do is to align the image horizontally with the rest of the content. Remember when we were talking about VStack?&lt;/p&gt;
&lt;p&gt;His job is to vertically align the list of items provided in his ViewBuilder block. It is clear, therefore, that it is necessary to slightly change the diagram of the views on which we are working on, taking care to add an additional variant of Stack provided by SwiftUI: HStack.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newhierarchylayout-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newhierarchylayout-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newhierarchylayout-962.avif 962w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newhierarchylayout-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newhierarchylayout-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-complex-views/newhierarchylayout-962.webp 962w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/newhierarchylayout.jpg&quot; alt=&quot;The new tree diagram of how we would like to modify our ContentView.&quot; width=&quot;962&quot; height=&quot;656&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.8 - The new tree diagram of how we would like to modify our ContentView.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Mario Rossi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Amministratore delegato&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/secondattempthstack-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/secondattempthstack-532.avif 532w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/secondattempthstack-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/secondattempthstack-532.webp 532w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/secondattempthstack.jpg&quot; alt=&quot;Second Attempt&quot; width=&quot;532&quot; height=&quot;1000&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.8a - Second Attempt&lt;/figcaption&gt;&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Much better!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;We still have to adjust the &lt;strong&gt;shape&lt;/strong&gt; and &lt;strong&gt;size&lt;/strong&gt; of the image. The first thing I want to do is tell our image that it should be resizable and keep its aspectRatio.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resizable&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aspectRatio&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;contentMode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .fit&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then I would like to give it a circular shape and force its size to  60pt:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;clipShape&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Circle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;frame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .center&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;and, finally, I would like to add some padding from the left, let's say 20points:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;All together:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resizable&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aspectRatio&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;contentMode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .fit&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;clipShape&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Circle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;frame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .center&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Mario Rossi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Amministratore delegato&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-spacer-object&quot;&gt;The Spacer object&lt;/h2&gt;
&lt;p&gt;At this point our &lt;strong&gt;CustomTableView&lt;/strong&gt; seems to be complete but a small problem still persists: it seems to be aligned to the center rather than to the left.&lt;/p&gt;
&lt;p&gt;The problem is related to the fact that Stacks by default - I remember that the main one we are working on expands horizontally (HStack) -  are designed to take all the space available on their main axis, dividing it equally between the children.&lt;/p&gt;
&lt;p&gt;Therefore, to be able to align the entire object on the left it is necessary to add an additional neutral view called Spacer. The View Spacer is a flexible view that expands automatically throughout the main axis of the stack in which it is inserted. We will add this View as the last element of our horizontal stack:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Image&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;photoThumb&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resizable&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aspectRatio&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;contentMode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .fit&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;clipShape&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Circle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;frame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .center&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;alignment&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Mario Rossi&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Amministratore delegato&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.subheadline&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fontWeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.thin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Spacer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Here's how our preview will look, once the job is complete:&lt;/p&gt;
&lt;figure class=&quot;figure-grid&quot;&gt;&lt;div&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/finalhierarchy-1-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/finalhierarchy-1-900.avif 900w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/finalhierarchy-1-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/finalhierarchy-1-900.webp 900w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/finalhierarchy-1.jpg&quot; alt=&quot;The final tree hierarchy of the CustomTableViewCell.&quot; width=&quot;900&quot; height=&quot;1000&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/finalrow-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/finalrow-631.avif 631w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/finalrow-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-complex-views/finalrow-631.webp 631w&quot; sizes=&quot;(min-width: 760px) 360px, 50vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-complex-views/finalrow.jpg&quot; alt=&quot;The final tree hierarchy of the CustomTableViewCell.&quot; width=&quot;631&quot; height=&quot;1000&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/div&gt;&lt;figcaption&gt;Fig.9 - The final tree hierarchy of the CustomTableViewCell.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: current version of Xcode11 contains a known problem that does not correctly resize the image when using the .fit option getting, instead some sort of stretch effect on the content.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the next chapter, we will see some rules of good conduct that try to make the code as minimal and compact as possible, adopting subviews extraction techniques. We will also see an introduction to passing parameters and how SwiftUI manages the status of its elements.&lt;/p&gt;
&lt;p&gt;-- 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI Programming: Classes and Structs in SwiftUI</title>
    <link href="https://www.sofapps.it/blog/swiftui-programming-classes-structs/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swiftui-programming-classes-structs/</id>
    <published>2020-01-07T00:00:00Z</published>
    <updated>2020-01-07T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Tutorial"/>
    <summary>Declaring a View as a plain class does not work, because a class can have subclasses and the View protocol could not guarantee uniqueness of Self. Marking the class final removes the problem. A class can then be used in SwiftUI when it is really needed.</summary>
    <content type="html">&lt;p&gt;I'm pretty sure that everyone had the following question, at least one time.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;If the concept behind a View is the protocol, what if I try to use a class instead?&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Let's try to analyze it in detail.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;   var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;      Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The code above, although syntactically perfect, produces an error. In fact, the compiler complains that the class itself is too mutable in the course of execution. In fact, a class is indeterminate by its nature: what would happen if ContentView itself had a subclass?&lt;/p&gt;
&lt;p&gt;The View protocol would not know how to guarantee uniqueness. * Self * would continue to refer to ContentView and the subclass would violate this rule.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SomeView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;   var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;      Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;or, simply:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;   var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;      Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;At this point - if it is really necessary - we can use a class to work in SwiftUI.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI Programming: The View Object</title>
    <link href="https://www.sofapps.it/blog/swiftui-programming-view-object/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swiftui-programming-view-object/</id>
    <published>2020-01-06T00:00:00Z</published>
    <updated>2020-01-06T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Tutorial"/>
    <summary>In SwiftUI a View is a struct that conforms to the View protocol, whose only requirement is a body returning another View. Complex interfaces are trees of small composable views. The some View return type is an opaque type: unlike a protocol, it keeps the concrete type, so a function can return only one kind of object.</summary>
    <content type="html">&lt;p&gt;We have seen that &lt;strong&gt;SwiftUI&lt;/strong&gt; is a declarative framework. The visual result of what we see in our device is the result of a series of statements we make to our compiler about how we would like to see our interface. But if the UIView was the beating heart in UIKit, what is the equivalent in SwiftUI? The answer is a new object, called View.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-view&quot;&gt;What is a View?&lt;/h2&gt;
&lt;p&gt;The first real and big difference compared to a &lt;strong&gt;UIView&lt;/strong&gt; is the fact that in SwiftUI a &lt;strong&gt;View&lt;/strong&gt; is a struct that conforms to a protocol. The basic example provided by Apple begins this way:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;   var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;      Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The one above is a fully functional SwiftUI object named ContentView and which contains (returns) a label with &amp;quot;Hello World&amp;quot; in its body.&lt;/p&gt;
&lt;p&gt;You will notice that I talked about the concept of &amp;quot;containing&amp;quot; (return was only hinted at in brackets). In fact, one of the cornerstones of SwiftUI is the reusability of the code and the concept of View reusable as if they were Lego ™ bricks.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-view-object/contentview-text-diagram-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-view-object/contentview-text-diagram-564.avif 564w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-view-object/contentview-text-diagram-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-view-object/contentview-text-diagram-564.webp 564w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-view-object/contentview-text-diagram.png&quot; alt=&quot;Tree like hierarchy about the above example.&quot; width=&quot;564&quot; height=&quot;250&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.1 - Tree like hierarchy about the above example.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;A view, therefore, defines a piece of our User Interface.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Everything in an app in SwiftUI can be traced back to a View. The latter defines, therefore, a piece of our interface. As a consequence, complex views are constructed from elementary bits that cooperate and work together creating a tree hierarchy. Behind the scenes, the compiler handles all the Views an translates them in a highly efficient data structure that display the required content on screen. But how does this composition work?&lt;/p&gt;
&lt;h2 id=&quot;one-only-requirement-body&quot;&gt;One only requirement: body&lt;/h2&gt;
&lt;p&gt;We said above that a View is a struct that conforms to the View protocol. The only requirement of this protocol is to provide our View with a body responsible for the content of our object. The body is a special closure that returns a content also in the form of a View. For example, in the code above provided by Apple:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;   var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;      Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;In the above case, the body of our View is a basic component, called Text, which in turn returns an object conforming to the some View type request expressed in the body. This syntax is part of a new concept presented with Swift 5.1 called Opaque Types. For now it is enough to know that the opaque type required by the body, allows us to effectively interchange objects of which we do not know the specific type in advance but which is well determined at the level of compilation (unlike a simple protocol).&lt;/p&gt;
&lt;h2 id=&quot;opaque-types&quot;&gt;Opaque types&lt;/h2&gt;
&lt;p&gt;Returning an opaque type seems very similar to using a protocol. However, these two constructs differ in the fact that the opaque type preserves the type. An opaque type refers to a specific type, even if the caller of the function is not able to see which type it is. A protocol, on the other hand, can refer to any type that conforms to it. The latter offer more flexibility with respect to the returned type. The opaque types, on the other hand, allow us to have specific guarantees regarding the returned type.&lt;/p&gt;
&lt;p&gt;Let's try to give an example, to clarify the concept better:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;mport UIKit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;protocol&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Humanoid&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Woman&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Humanoid &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Man&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Humanoid &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; child&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Humanoid {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;	Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Woman&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Man&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The Humanoid protocol is adopted by two structures: Man and Woman. The child function, returns a Humanoid type that can be equally probable one of the two cases mentioned. At this point, we create two humanoid instances:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; first &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; child&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; second &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; child&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;and since we are curious to know if our children are male or female, let's try to compare them:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;(first &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; second)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The compiler, at this point, will blame us - rightly - about the fact that the humanoid class is not comparable because it does not adopt the Equatable protocol. Not bad, you'll think. Let's try to adopt it:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-view-object/opaqueerror-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming-view-object/opaqueerror-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming-view-object/opaqueerror-1000.avif 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming-view-object/opaqueerror-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming-view-object/opaqueerror-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming-view-object/opaqueerror-1000.webp 1000w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming-view-object/opaqueerror.png&quot; alt=&quot;Playground output.&quot; width=&quot;1000&quot; height=&quot;481&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;figcaption&gt;Fig.2 - Playground output.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Problem is that Humanoid cannot be compared because Swift has no guarantee that the returned items are of a comparable type. I recall that any structure can adopt the protocol, by implementing the required methods.&lt;/p&gt;
&lt;p&gt;To solve this problem, opaque types are born. The code above can be transformed as follows:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIKit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;protocol&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Humanoid&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Equatable&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Woman&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Humanoid &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Man&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Humanoid &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; boy&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Humanoid {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;	Man&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; girl&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Humanoid {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;	Woman&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; primogenito &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; boy&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; secondogenito &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; girl&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;An important observation about the code above is that, as you will notice, I had to create two different children() functions (one for female - bambina and one for Male - bambino) because one of the main requirements when working with an opaque type is &lt;strong&gt;that the methods must return only one type of object&lt;/strong&gt;. You will find this concept very often in SwiftUI when we will work with Views.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI Programming: An Introduction</title>
    <link href="https://www.sofapps.it/blog/swiftui-programming-introduction/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swiftui-programming-introduction/</id>
    <published>2020-01-05T00:00:00Z</published>
    <updated>2020-01-05T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Tutorial"/>
    <summary>SwiftUI is Apple's answer to the declarative frameworks that have spread on the web and in mobile development. There is no controller layer: the interface is a function of state and is rebuilt when the state changes. This post opens a series of study notes on the framework.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;SwiftUI&lt;/strong&gt; certainly marks the beginning of a new chapter in the history of development at Apple. For years we have witnessed the proliferation of frameworks based on the concept of declarative interfaces; the web is a prime example of this phenomenon, but there are other notable examples in the field of mobile development. We are constantly amused with marketing messages that state how:&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;maintaining a single codebase for all platforms is the best way to increase business productivity and provide effective solutions to our customers.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;React Native&lt;/strong&gt; (Facebook) and &lt;strong&gt;Flutter&lt;/strong&gt; (Google) are an excellent example of this proposition. It is not the purpose of this article to make a comparative analysis of these technologies; the point for which these two examples have been cited is to show how the software trend of recent years is moving in different directions from those we have been used to up to now.&lt;/p&gt;
&lt;p&gt;Our devices are increasingly powerful and this power finds its natural placement in increasingly sophisticated and complex interfaces and interaction paradigms. Last year, &lt;a href=&quot;https://www.sofapps.it/blog/iphone-x-peripheral-vision/&quot;&gt;I wrote a piece&lt;/a&gt; about the release of iPhone X and the feeling of fluidity that this new device, combined with the latest stylistic choices of iOS 11 and 12, had aroused me.&lt;/p&gt;
&lt;p&gt;Smooth, continuous and consistent animations, gestures merged within the navigation experience. These are just some examples of what I am trying to convey to you: the expectation bar has risen once again and these new features are not easily expressed with a traditional framework.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;The discrete nature of imperative languages is in great difficulty, compared to the sense of continuity and fluidity imposed by the new interfaces.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Apple has always been a very conservative company (&lt;strong&gt;Objective-C&lt;/strong&gt; continues to operate and compile quite well) in relation to its development environments and, in general, with respect to its entire ecosystem. The introduction of &lt;strong&gt;Swift&lt;/strong&gt;, 5 years ago, with its new paradigms and its burst of modernity had already been a big sign of change by Cupertino. But it was clear that it was not enough. So, surprisingly for everyone, here comes Apple's response to the other giants of the web: &lt;strong&gt;SwiftUI&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;SwiftUI is a declarative component-oriented framework. Let's forget, therefore, the &lt;strong&gt;MVC&lt;/strong&gt; pattern where the controllers mediated between views and models. All we have in SwiftUI is a state and a view derived from the state. As soon as the status changes, SwiftUI reconstructs the interface taking these changes into account.&lt;/p&gt;
&lt;p&gt;Those that follow are our personal travel notes, during the study of this new and, to some extent, mysterious framework. We thought it useful to share this information with all of you in the hope that it will be a starting point for learning something truly exciting.&lt;/p&gt;
&lt;p&gt;--Have a good trip!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>TextField and UIViewRepresentable</title>
    <link href="https://www.sofapps.it/blog/textfield-uiviewrepresentable/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/textfield-uiviewrepresentable/</id>
    <published>2019-06-28T00:00:00Z</published>
    <updated>2019-06-28T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Swift"/>
    <category term="UIKit"/>
    <category term="Tutorial"/>
    <summary>The SwiftUI TextField of iOS 13 beta 2 could not move focus between fields and never called onCommit. The post wraps a UITextField that is its own delegate in a UIViewRepresentable struct, using closures for changes and end of editing and view tags to pass focus to the next field.</summary>
    <content type="html">&lt;p&gt;At a glance, when I first tried SwiftUI after the WWDC19 introduction, one of the biggest concern was certainly related to the TextField object: there was no way to dispose the keyboard, nor a way to move the focus from one TextField to another.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;probably, some details were not yet ready during the initial presentation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;iOS13 beta2&lt;/strong&gt;, along with many other improvements, seems to solve at least in part the problems related to the &lt;strong&gt;TextField&lt;/strong&gt;: when the enter key is pressed, the keyboard is now dismissed correctly. There are no clues, however, about a mechanism to &lt;strong&gt;change the focus&lt;/strong&gt; between &lt;strong&gt;multiple&lt;/strong&gt; TextField(s) within the same View container. Unfortunately, we must also report an &lt;strong&gt;important bug&lt;/strong&gt; in beta2 that affects the call mechanism for the &lt;strong&gt;onCommitHandler&lt;/strong&gt; closure when the keyboard is dismissed: the latter is never called at all.&lt;/p&gt;
&lt;p&gt;In this article we will try to work around all these problems by creating a custom &lt;strong&gt;TextField&lt;/strong&gt; taking all the good that is currently in &lt;strong&gt;SwiftUI&lt;/strong&gt; and &lt;strong&gt;UIKit&lt;/strong&gt;. The smartest readers, probably, will already figured out where I want to go:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We will build a custom component in UIKit that uses the old fashioned and perfectly functioning UITextField and we will expose it in SwiftUI through the UIViewRepresentable protocol.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;uitextfield-and-delegates&quot;&gt;UITextField and delegates&lt;/h2&gt;
&lt;p&gt;UIKit provides an object called &lt;strong&gt;UITextField&lt;/strong&gt; which take advantage of the &lt;strong&gt;delegate technique&lt;/strong&gt; in order to offer a fluid and effective keyboard experience.&lt;/p&gt;
&lt;p&gt;What we will do is creating a class that inherits from &lt;strong&gt;UITextField&lt;/strong&gt; and, simultaneously, adopts the &lt;strong&gt;UITextFieldDelegate&lt;/strong&gt; protocol. This way we will have a single object to expose for integration with &lt;strong&gt;SwiftUI&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The first thing to do is to declare our class, which we will call &lt;strong&gt;WrappableTextField&lt;/strong&gt;:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; WrappableTextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UITextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;UITextFieldDelegate &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; textFieldChangedHandler: ((&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; onCommitHandler: (()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; textFieldShouldReturn&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; textField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UITextField) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; textField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; textField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UITextField, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;shouldChangeCharactersIn&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: NSRange, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;replacementString&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; textFieldDidEndEditing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; textField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UITextField) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The code above shows the skeleton of delegate methods we will implement to complete the Wrapper class.&lt;/p&gt;
&lt;p&gt;As anticipated, our class extends UITextField, adopting the delegated protocol UITextFieldDelegate. We also added two local variables that contain two custom optional closures. Respectively:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The closure &lt;strong&gt;textFieldChangedHandler&lt;/strong&gt;, will be invoked whenever there is a change of the UITextField.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The closure &lt;strong&gt;onCommitHandler&lt;/strong&gt;, will be invoked at the end of editing by pressing the Enter key.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s see now, step by step the individual method implementations that will be added to our class.&lt;/p&gt;
&lt;h4 id=&quot;textfield-shouldchangecharactersinrange-replacementstring&quot;&gt;textField:shouldChangeCharactersInRange:replacementString:&lt;/h4&gt;
&lt;p&gt;The delegate method shouldChangeCharactersInRange:replacementString: is automatically invoked by the system whenever we type something on the keyboard. It allows us to perform checks on the content, returning a boolean value depending on whether the content entered is allowed or not by our validation policies.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; textField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; textField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UITextField, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;shouldChangeCharactersIn&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: NSRange, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;replacementString&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; currentValue &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; textField.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; NSString&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; proposedValue &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; currentValue.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;replacingCharacters&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; range, with&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        textFieldChangedHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(proposedValue &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;In our case, it will be suffice to compose the new string resulting from the insertion of the user input and the one currently present on the UITextField. For simplicity, we convert the String type into a foundation NSString, which provides all the tools to communicate directly with the NSRange object supplied as an input parameter by the method.&lt;/p&gt;
&lt;p&gt;Once the string has been converted, we apply on it the transformation proposed through the method:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;replacingCharacters(in: range, with: string)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Passing the two values supplied as input by the method as parameters. Respectively, range and the string entered by the user. The result will be the composition between the input provided by the user and the current content of the UITextField.&lt;/p&gt;
&lt;p&gt;This value will be the one we will provide in input to the closure defined previously:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;textFieldChangedHandler?(proposedValue as String)&lt;/code&gt;&lt;/p&gt;
&lt;h4 id=&quot;textfielddidendediting&quot;&gt;textFieldDidEndEditing:&lt;/h4&gt;
&lt;p&gt;The implementation of this method, triggered by the system to complete the editing phase, is very simple: it will only have to invoke our custom closure defined previously. This way we will be able to execute an arbitrary chunk of code every time the editing is completed.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; textFieldDidEndEditing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; textField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UITextField) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    onCommitHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h4 id=&quot;textfieldshouldreturn&quot;&gt;textFieldShouldReturn:&lt;/h4&gt;
&lt;p&gt;The last method we have to implement is textFieldShouldReturn. Its implementation will allow us to build a very simple mechanism to move focus from our TextField into other similar classes contained within the same container view. Let’s see how it works.&lt;/p&gt;
&lt;p&gt;The first thing we do is to ask the current textField element a reference to its own superview?.superview? following a pattern similar to the one depicted in the following schema:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-1-480.avif 480w, https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-1-960.avif 960w, https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-1-1344.avif 1344w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-1-480.webp 480w, https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-1-960.webp 960w, https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-1-1344.webp 1344w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-1.jpg&quot; alt=&quot;Diagram of a VStack containing two SATextField views, each with a WrapperView inside, with .superView? arrows going up to the container&quot; width=&quot;1344&quot; height=&quot;1167&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;If a valid object is returned, we will invoke its viewWithTag method, passing the current tag incremented by one. This way we have managed to create a very elementary scaffolding workflow, that allows us to go back up to the container and ask it for other views with a specific tag.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; textFieldShouldReturn&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; textField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UITextField) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; nextField &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; textField.superview&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.superview&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;viewWithTag&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;textField.tag &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; UITextField {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        nextField.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;becomeFirstResponder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        textField.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resignFirstResponder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If the returned value exists and is of type UITextField, then we have found another UITextField and we can pass the control to it. Otherwise, we will simply dismiss the keyboard.&lt;/p&gt;
&lt;p&gt;Our Wrappable class is ready. Now, we just have to plug it into SwiftUI.&lt;/p&gt;
&lt;h3 id=&quot;uiviewcontrollerrepresentable&quot;&gt;UIViewControllerRepresentable&lt;/h3&gt;
&lt;p&gt;SwiftUI provides a very useful protocol called UIViewControllerRepresentable allowing us to expose all those UIKit objects that, to date, have not been natively integrated into SwiftUI.&lt;/p&gt;
&lt;p&gt;By adopting this protocol it is possible to construct an object that exposes the content of an UIView natively to SwiftUI. It require to implement just two methods:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SATextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIViewRepresentable &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; makeUIView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UIViewRepresentableContext&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;SATextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; WrappableTextField {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; updateUIView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; uiView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: WrappableTextField, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UIViewRepresentableContext&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;SATextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;	...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The first method is responsible for the creation of our UIView as well as providing it to SwiftUI in a compatible some View format allowed by the SwiftUI protocol as we saw in the previous tutorials.&lt;/p&gt;
&lt;p&gt;The second method will be invoked whenever our UIView needs to be updated to reflect a change in the user interface (a bit like the body property we saw in SwiftUI native objects).&lt;/p&gt;
&lt;p&gt;Finally, let’s add some local variables to our object that we will use to drive the behavior of the WrappableTextField class previously declared:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SATextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIViewRepresentable &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; tmpView &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; WrappableTextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; tag:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; placeholder:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; changeHandler:((&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; onCommitHandler:(()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;These variables will be the required parameters to create the SwiftUI object. They will be passed to the previously instantiated Wrapper class and express respectively: the value of the tag to be associated to the TextField, the closures necessary to manage the user input changes, the end editing and the value to associate to the placeholder of our UITextField.&lt;/p&gt;
&lt;p&gt;The content of the makeUIView method, just associates the parameters entered by the user during the SwiftUI object creation with the corresponding parameters exposed by the WrappableTextField class.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; makeUIView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UIViewRepresentableContext&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;SATextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; WrappableTextField {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    tmpView.tag &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; tag&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    tmpView.delegate &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; tmpView&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    tmpView.placeholder &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; placeholder&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    tmpView.onCommitHandler &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; onCommitHandler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    tmpView.textFieldChangedHandler &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; changeHandler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; tmpView&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The updateUIView method will set the hugging priority of our UITextField to adapt to all available space within the Container View, consistently with all the other objects:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; updateUIView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; uiView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: WrappableTextField, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: UIViewRepresentableContext&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;SATextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    uiView.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;setContentHuggingPriority&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.defaultHigh, for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .vertical&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    uiView.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;setContentHuggingPriority&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.defaultLow, for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .horizontal&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h3 id=&quot;wrap-it-up-a-real-world-example&quot;&gt;Wrap it up: a real world example&lt;/h3&gt;
&lt;p&gt;Let’s try using our brand new SATextField in a practical example:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @State&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; username:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @State&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; email:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;username&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Spacer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SATextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;tag&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, placeholder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;@username&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, changeHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; { (newString) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                self.username &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; newString&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            }, onCommitHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;commitHandler&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SATextField&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;tag&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, placeholder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;@email&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, changeHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; { (newString) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                self.email &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; newString&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            }, onCommitHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;commitHandler&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;All done folks! In a few lines of code we have created a TextField object responsive to the focus changes and the end editing completion, waiting for the next beta of iOS13 to solve the current problems of the native TextField object.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-2.gif&quot; alt=&quot;Screen recording on an iPhone of the two custom text fields, shown in red, with the placeholders @username and @email&quot; width=&quot;500&quot; height=&quot;1085&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/figure&gt;
</content>
  </entry>
  <entry>
    <title>A TicTacToe game in SwiftUI</title>
    <link href="https://www.sofapps.it/blog/tictactoe-swiftui/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/tictactoe-swiftui/</id>
    <published>2019-06-18T00:00:00Z</published>
    <updated>2019-06-18T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Swift"/>
    <category term="UIKit"/>
    <category term="Tutorial"/>
    <summary>The post builds a Human vs Machine TicTacToe in SwiftUI beta, in less than 160 lines. The Square model publishes changes through a Combine PassthroughSubject, a SquareView observes it with @ObjectBinding, and a @State flag drives the game over alert in ContentView.</summary>
    <content type="html">&lt;p&gt;Today we will try to build a TicTacToe game in less than 160 lines with SwiftU Apple’s new declarative framework that promises to supplant its brother UIKit in the near future. Let’s open Xcode.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In these hours the beta2 came out together with macOS catalina beta2. I strongly advise you to install both of them, since we have noticed an overall remarkable improvement in performance as well as an improved Xcode responsiveness in all respects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once opened Xcode, we will create a new project, let’s name it TicTacToe and make sure that the tick in SwiftUI is enabled. Press next and choose a folder to store your new project.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/tictactoe-swiftui/fig-1-480.avif 480w, https://www.sofapps.it/blog/tictactoe-swiftui/fig-1-726.avif 726w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/tictactoe-swiftui/fig-1-480.webp 480w, https://www.sofapps.it/blog/tictactoe-swiftui/fig-1-726.webp 726w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/tictactoe-swiftui/fig-1.jpg&quot; alt=&quot;Xcode new project dialog with the product name TicTacToe and the Use SwiftUI checkbox enabled&quot; width=&quot;726&quot; height=&quot;522&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Once the initialization phase is complete, Xcode shows the skeleton for the pre-generated project. Move to ContentView.swift and let’s start immediately shaping the logic of our game.&lt;/p&gt;
&lt;p&gt;In the TicTacToe game, the two opponents challenge each other, each taking an X or O mark, in a 3x3 board. The winner is the one who is the first to line up three identical signs horizontally, vertically or diagonally.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The first thing to do, therefore, will be to create a model that reflects what has just been said.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s write an enum that reflects the status of a box. This may be empty, occupied by us or by the computer.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SquareStatus&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; empty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; visitor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; home&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To play we will need a 3x3 chessboard. So, try to define the model for a single square in the board:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Square&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; BindableObject &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; didChange &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; PassthroughSubject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Never&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; status: SquareStatus {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        didSet&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            didChange.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    init&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: SquareStatus) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        self.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The Square class adopts the &lt;strong&gt;BindableObject&lt;/strong&gt; protocol. Objects that adopt this protocol are objects that notify subscribers in the SwiftUI framework when one or more properties in it change.&lt;/p&gt;
&lt;p&gt;To do this it is necessary to adopt the protocol correctly, adding an instance that publishes an event when an object changes. This instance is called didChange:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; didChange &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; PassthroughSubject &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Never&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; ()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;PassthroughtSubject is a class made available by the Combine framework, which allows us to publish a notification to all applicants. The notification has two parameters, the output and a possible error.&lt;/p&gt;
&lt;p&gt;For now, all that we want is to notify all applicants that something has changed into the Square object. So, since we are not interested in any of the two parameters, we will pass Void for the first parameter and Never for the second. The first indicates that we do not pass any output. The second indicates that there is no possibility of error.&lt;/p&gt;
&lt;p&gt;Next, we define the property status of our box and, inside it, we’ll add a mechanism that sends a notification when we change its value:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; status: SquareStatus {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    didSet&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        didChange.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We can move, next, on to the actual Model that define the game and the chessboard. We will call it ModelBoard:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ModelBoard&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; squares &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [Square]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    init&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            squares.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Square&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .empty&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We start with the declaration of the array variable that will host the individual pieces of the board. In the init function we are going to add 9 elements of type Square all with status .empty&lt;/p&gt;
&lt;p&gt;At the end of the game we will need a method to bring the game back to its initial state:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; resetGame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .empty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now we need to have a way to check if the game is over.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A game ends if there are no more boxes available or if one of the two players align three symbols before the other.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; gameOver: (SquareStatus, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    get&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; thereIsAWinner &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .empty {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;thereIsAWinner, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        } &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .empty {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.empty, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.empty, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The getter variable thereIsAWinner will simply check all winning occurrences:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; thereIsAWinner:SquareStatus {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    get&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        } &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }  &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }  &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }  &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }  &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }  &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }  &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .empty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The checkIndex function takes an array of integers (indexes) as input and returns an optional SquareStatus: .home or .visitor if there’s a winner; nil otherwise:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checkIndexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; indexes&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;]) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; SquareStatus&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; homeCounter:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; visitorCounter:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anIndex &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; indexes {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aSquare &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;anIndex&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aSquare.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .home {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            homeCounter &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; homeCounter &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        } &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aSquare.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .visitor {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            visitorCounter &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; visitorCounter &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; homeCounter &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .home&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; visitorCounter &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .visitor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We need a way to make a move. For our human player we will check if the selected square is empty. If yes, then we will change its status to .home&lt;/p&gt;
&lt;p&gt;Since, we’re only implementing a Human vs Machine game, we also need to trigger the computer move at the end.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; makeMove&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;player&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;:SquareStatus) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .empty {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; player&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; player &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .home { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aiMove&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The move of artificial intelligence is really simple: we only collect a random index, check if it is empty and if this’s the case we will fill it with the .visitor flag.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; aiMove&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anIndex &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;makeMove&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; anIndex, player&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .visitor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; gameOver.1 &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        anIndex &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now that the model is ready, we need to interact with SwiftUI in order to build a View that could respect the Square Model. Let’s call it SquareView:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @ObjectBinding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; dataSource:Square&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; action: () &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Void&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        Button&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            self.action&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;(dataSource.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .empty) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                (dataSource.status &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .visitor) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;X&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;0&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot; &quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;frame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;minWidth&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, minHeight&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;background&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Color.gray&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;EdgeInsets&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, leading&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bottom&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, trailing&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;First of all, we add an @ObjectBinding property wrapper in front of the Square datasource.&lt;/p&gt;
&lt;p&gt;This way we’re telling to SwiftUI that the SquareView is interested in changing notifications from the model. When a change will come, SwiftUI will automatically trigger a new body for the SquareView.&lt;/p&gt;
&lt;p&gt;Inside the body we’re conditionally check if there’s a status other than .empty. If so, we write X or O accordingly.&lt;/p&gt;
&lt;p&gt;.frame, .background and .padding are all cosmetic adjustments related to the Square.&lt;/p&gt;
&lt;p&gt;Finally, we need to modify our ContentView in order to house the chessBoard by creating a private var for that purpouse, naming it checker:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ContentView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; View &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; checker &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ModelBoard&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    @State&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; isGameOver &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We also define a @State property for checking if the game is finished; we need to define it as a @State property, since we would like to refresh the ContentView body once the game is completed.&lt;/p&gt;
&lt;p&gt;Since every SquareView is the same and it’s behaviour change only based on index, we define also a buttonAction method:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; index&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    _&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.checker.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;makeMove&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; index, player&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .home&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    self.isGameOver &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.checker.gameOver.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This way, every SquareView will invoke the method with its specific index and the relevant code is executed with respect to the specified position.&lt;/p&gt;
&lt;p&gt;Finally, we can build the whole body, reflecting the 9x9 SquareView(s):&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; body: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;some&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; View {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    VStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        HStack&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            SquareView&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataSource&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; checker.squares&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;buttonAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;One last thing, is regarding a feedback for the user: we want to notify the user with a popup when either the game is end or someone will win.&lt;/p&gt;
&lt;p&gt;To make this, we could use the .presentation View modifier. In it’s simple form it takes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A conditional boolean to discern if it should appear or not&lt;/li&gt;
&lt;li&gt;A message parameter with a Text for the body of the alert&lt;/li&gt;
&lt;li&gt;A dismissButton: with an Alert.Button&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;presentation&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;$isGameOver&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { () &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Alert &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    Alert&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Game Over&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;          message&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;self.checker.gameOver.0 &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .empty &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            (self.checker.gameOver.0 &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .home) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;You Win!&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;iPhone Wins!&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            :&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Parity&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, dismissButton&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Alert.Button.destructive&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Ok&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, onTrigger&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                self.checker.resetGame&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;That’s all folks! As promised, in less than 160 lines of code we have a fully working TicTacToe game. If we Build and Run our code our application will looks like the following:&lt;/p&gt;
&lt;figure class=&quot;img-narrow&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/tictactoe-swiftui/fig-2.gif&quot; alt=&quot;The running TicTacToe app on an iPhone simulator, showing a three by three grid of gray squares&quot; width=&quot;332&quot; height=&quot;720&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/figure&gt;
</content>
  </entry>
  <entry>
    <title>iPadOS, Catalyst and Sidecar</title>
    <link href="https://www.sofapps.it/blog/ipados-catalyst-sidecar/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/ipados-catalyst-sidecar/</id>
    <published>2019-06-17T00:00:00Z</published>
    <updated>2019-06-17T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Swift"/>
    <category term="UIKit"/>
    <category term="Editorial"/>
    <summary>After a week of testing an iPad Pro, the author concludes it cannot replace his MacBook Pro for software development, although it works very well for notes, email and writing. The real change is in software: iPadOS, Catalyst and Sidecar show Apple's idea of convergence between devices without bringing touch to the Mac. The post sees them as the start of a change of habits for people who still depend on the traditional desktop.</summary>
    <content type="html">&lt;p&gt;I had decided not to comment on the new iPad Pro from the day it first came out. After all, I thought it was just one more commercial move by an Apple led by Tim Cook, a skilled businessman and only remotely a visionary, aiming at profit and sales in a market segment that is by now saturated. No, talking about it would only have fed the buzz of blogs and fanatics, one way or another.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I was wrong. This product deserves all our attention, for a number of reasons I will try to explain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let's take it in order. The tablet market is saturated and in steep decline. KGI claims that, together with iPhone, it will contribute to an unprecedented drop in iOS device sales over the 2016/2020 period. That may well be true, but it does not mean there is no room to innovate.&lt;/p&gt;
&lt;p&gt;The average user will probably notice these innovations late, or maybe not at all, but that does not mean Cupertino is not trying to innovate. What we expect from a tablet, as Phil Schiller theatrically explained during the presentation of 21 March 2016, is the ability to replace our old personal computers in all our daily activities. Since the first iPad Pro, Apple has claimed that the new iPad is the ideal replacement for the “boring” PC of the 1980s. Better still, it is the modern interpretation of how we express ourselves, create, study and have fun. Is that true?&lt;/p&gt;
&lt;p&gt;Taking advantage of the news presented at WWDC 2019, I decided to run an in-depth test with an iPad Pro to understand the state of the art and how close the claim above is to reality. I did not use the keyboard sold as an accessory, for a simple reason: it can only be used in a forced position (so no extreme typing on the couch or in bed) and it costs a fortune. For this week of testing I chose a far more capable and comfortable Apple Bluetooth keyboard, so I can move and sit however and wherever I want. Besides, when I am on the move I really do not see what I would do with a physical keyboard at all.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Apple Pencil, on the other hand, is spectacular. Using a pencil is so deeply rooted in our modern culture that using one with an iPad feels almost more natural than using our fingers (for some activities fingers are still better, in terms of effectiveness and feedback).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The new revision of the pen has also come a long way since the first version, which had a cap hiding the charging connector (practically lost before you even opened the box), no place to store the pen safely on the iPad and, a detail I would gladly skip, a truly controversial charging mechanism.&lt;/p&gt;
&lt;p&gt;We are certainly at a turning point, but saying that the new iPad replaces the personal computer is at the very least a stretch. My job is writing applications as well as coordinating a team of developers. I call all of these operations “complex”, not because of their content but because of the way they are carried out. Picture a typical day with a hundred emails to answer, twenty phone calls to take notes on, two or three Xcode projects open for code review and an endless number of documents to consult, annotate and write. I am absolutely convinced this job is bad for one's mental and physical health, but it is too late to change course now and, deep down, I like it a lot.&lt;/p&gt;
&lt;p&gt;Clearly, with these premises, the iPad Pro cannot possibly replace my MacBook Pro: too many things are more cumbersome and less precise. At the same time, some things are extremely simple, fast and effective. Taking notes, answering email, writing this article and communicating are disarmingly easy.&lt;/p&gt;
&lt;p&gt;Don't get me wrong, this is not about power: the new iPad has plenty of it, and a quick search turns up hundreds of power comparisons between iPad and MacBook. In terms of technology we are looking at a gem that has nothing to envy a high end laptop.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Fortunately for us, the problem lies elsewhere. It is clear that iOS as we know it shows its limits. Anyone who used and worked with the first version of iOS cannot help noticing the incredible changes and effort of the past years. iOS 7 changed the way we think about interfaces; iOS 8 showed us that it is not a matter of how many apps you can keep open at the same time but of how you make them talk to each other; iOS 9 consolidated communication between devices, making it a pleasure for the mind to move from one device to another. iOS 10, 11 and 12 were a continuous refinement of details of stability, style, usability and experience, which few others in the software world have had the courage to pursue over such a long period: it takes courage not to flood every new release of the operating system with half-tested, hard to use and poorly thought out features.&lt;/p&gt;
&lt;p&gt;Something was still missing to close the circle. Microsoft tried, in its own way, to represent that missing piece with Windows 10 and Microsoft Surface. Google has been trying for years with the idea of a converging web (and browser) where you can do everything, while waiting for Fuchsia.&lt;/p&gt;
&lt;p&gt;Apple, instead, with a surprise move, showed its vision of the long awaited convergence between devices. I am talking about iPadOS and Catalyst.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-1-480.avif 480w, https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-1-960.avif 960w, https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-1-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-1-480.webp 480w, https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-1-960.webp 960w, https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-1-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-1.jpg&quot; alt=&quot;A speaker on the WWDC stage next to the Project Catalyst slide, with an orange icon of overlapping windows and a laptop&quot; width=&quot;1400&quot; height=&quot;933&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Being a big company is not easy. It confines you to a difficult position where everyone always expects “something more”. Apple therefore had to express this concept in a different way: Think different, as someone would say.&lt;/p&gt;
&lt;p&gt;No Apple user would have been satisfied with having the desktop and the Finder bar on their iDevice. After all, Apple users are known to be a bit more demanding and creative.&lt;/p&gt;
&lt;p&gt;And so here comes iPadOS. It is not a new operating system but simply an extension of the iOS we have grown used to and love. Extensions that enable new, never seen features: Multitasking, Desktop and interconnection features we had all only dreamed of. Taking a close look at the APIs available with iOS 13, you can see an endless supply of new resources for building drivers and USB communication and interface mechanisms. Fantastic.&lt;/p&gt;
&lt;p&gt;I do not think we will get a flat, obvious convergence like the one Microsoft showed and talked about. I do not think my MacBook's screen will ever become touch. At the same time, though, I see that bringing a native iPad application to macOS is child's play and that my iPad's screen can become the long desired tactile surface for talking to my computer through Sidecar.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-2-480.avif 480w, https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-2-960.avif 960w, https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-2-1384.avif 1384w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-2-480.webp 480w, https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-2-960.webp 960w, https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-2-1384.webp 1384w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/ipados-catalyst-sidecar/fig-2.jpg&quot; alt=&quot;A woman in a library drawing with an Apple Pencil on an iPad next to a MacBook Pro, both showing the same illustration of a whale (Sidecar)&quot; width=&quot;1384&quot; height=&quot;778&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Apple will try to show that style and an overall vision, above all, can be the start of a subtle and elegant change, no less effective for that, in the way we talk to machines.&lt;/p&gt;
&lt;p&gt;In my personal view, this June WWDC presented a lot of great news, among them the introduction of iPadOS, Continuity and Catalyst.&lt;/p&gt;
&lt;p&gt;It will probably be an event that goes down in history and marks an epochal passage for everyone who still needs the old desktop and the Finder bar to work. If you do not believe me, try connecting a keyboard to the new iPad Pro and press ⌘+Tab.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI programming</title>
    <link href="https://www.sofapps.it/blog/swiftui-programming/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swiftui-programming/</id>
    <published>2019-06-13T00:00:00Z</published>
    <updated>2019-06-13T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="SwiftUI"/>
    <category term="Swift"/>
    <category term="UIKit"/>
    <category term="Tutorial"/>
    <category term="Editorial"/>
    <summary>SwiftUI is Apple's answer to the declarative, reactive frameworks that spread on the web and in mobile development. Instead of controllers mediating between views and models, you describe a state and a view derived from it, and SwiftUI rebuilds the interface when the state changes. This post opens a series of study notes on the framework.</summary>
    <content type="html">&lt;p&gt;SwiftUI certainly marks the beginning of a new era in Apple’s programming history. In the last years we have witnessed the proliferation of frameworks based on the concept of declarative interfaces and reactive programming; the web is a prime example of this phenomenon, but there are other notable examples in the field of mobile development. We are constantly amused with marketing messages that state how:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;maintaining a single codebase for all platforms is the best way to increase business productivity and provide effective solutions to our customers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;React Native (Facebook) and Flutter (Google) are an excellent example of this proposition. It is not the purpose of this article to make a comparative analysis of these technologies; the point for which these two examples have been cited is to show how the software trend of recent years is moving in different directions from those we have been used to, up to now.&lt;/p&gt;
&lt;p&gt;Our devices are increasingly powerful and this power finds its natural placement in increasingly sophisticated and complex interfaces and interaction paradigms. Last year, &lt;a href=&quot;https://blog.prototypr.io/iphone-x-and-peripheral-vision-813b2599bf8c&quot;&gt;I wrote a piece&lt;/a&gt; about the release of iPhone X and the feeling of fluidity that this new device, combined with the latest stylistic choices of iOS 11 and 12, had aroused me.&lt;/p&gt;
&lt;p&gt;Smooth, continuous and consistent animations, gestures merged within the navigation experience. These are just some examples of what I am trying to convey to you: the expectation bar has risen once again and these new features are not easily expressed with a traditional framework.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The discrete nature of imperative languages is in great difficulty, compared to the sense of continuity and fluidity imposed from new interface paradigms.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Apple has always been a very conservative company (Objective-C continues to operate and compile quite well) in relation to its development environments and, in general, with respect to its entire ecosystem.&lt;/p&gt;
&lt;p&gt;The introduction of Swift, 5 years ago, with its new paradigms and its burst of modernity had already been a big sign of change by Cupertino. But it was clear that it was not enough. So, surprisingly for everyone, here comes Apple’s response to the other giants of the web: SwiftUI.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming/fig-1-480.avif 480w, https://www.sofapps.it/blog/swiftui-programming/fig-1-960.avif 960w, https://www.sofapps.it/blog/swiftui-programming/fig-1-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swiftui-programming/fig-1-480.webp 480w, https://www.sofapps.it/blog/swiftui-programming/fig-1-960.webp 960w, https://www.sofapps.it/blog/swiftui-programming/fig-1-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swiftui-programming/fig-1.png&quot; alt=&quot;Xcode showing a ContentView.swift file with a VStack and HStack of Text views, and the live preview with the text Turtle Rock&quot; width=&quot;1400&quot; height=&quot;996&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;SwiftUI is a declarative component-oriented framework. Let’s forget, therefore, the MVC pattern where the controllers mediated between views and models. All we have in SwiftUI is a state and a view derived from the state. As soon as the status changes, SwiftUI reconstructs the interface taking these changes into account.&lt;/p&gt;
&lt;p&gt;In a series of post, I’ll try to share my thoughts and personal travel notes, during the study of this new and, to some extent, mysterious framework.&lt;/p&gt;
&lt;p&gt;I thought it could be useful, in the hope that it could be a starting point for learning something new and truly exciting.&lt;/p&gt;
&lt;p&gt;-Happy Coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>WWDC18: ARKit2 a 2D tracking performances comparison</title>
    <link href="https://www.sofapps.it/blog/arkit2-image-tracking-performance/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/arkit2-image-tracking-performance/</id>
    <published>2018-06-18T00:00:00Z</published>
    <updated>2018-06-18T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="Swift"/>
    <category term="UIKit"/>
    <category term="Tutorial"/>
    <category term="ARKit"/>
    <category term="WWDC18"/>
    <summary>ARKit 2 introduces ARImageTrackingConfiguration, which tracks 2D images in real time and handles images that leave the view, while iOS 11 only offers ARWorldTrackingConfiguration with weaker tracking. The article builds a small app that overlays text on business cards, adds a timer based workaround to remove stale nodes on iOS 11, and loads the reference images from a remote JSON. It also notes an Xcode 10 beta bug that blocks image detection on iOS 11 devices.</summary>
    <content type="html">&lt;p&gt;One of the most interesting tech trend of the last year was for sure Augmented Reality. All the big have done something related to it, including Apple. They spent a lot of resources and time dealing with this topic and as Tim Cook said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…Augmented reality could be the next big thing…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If 2017 was the milestone year for the introduction of a complete framework that deals with AR, the 2018 is for sure the maturity year for this technology following the introduction of ARKit2.&lt;/p&gt;
&lt;p&gt;A lot of things have changed in favour of usability, maintanability and simplicity: all things that could help a lot spreading a technology to the mass. The rest of the article is about my personal experience with the new ARKit framework underlining the improvements and differences between iOS11 and iOS12. As any good dev article, we need a case study to deal with in order to better explain the topic. So, here it is.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We will create a simple Application that uses Augmented Reality to show you special offers and additional information when pointing out business cards.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Optionally, the application will load the required information from a remte JSON and then will show to the user the corresponding visual enhancements when needed.&lt;/p&gt;
&lt;p&gt;The first thing is opening Xcode and create a new AR project filling all the relevant stuff:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-1-480.avif 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-1-960.avif 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-1-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-1-480.webp 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-1-960.webp 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-1-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-1.png&quot; alt=&quot;Xcode template chooser with Augmented Reality App selected under iOS Application&quot; width=&quot;1400&quot; height=&quot;1013&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;By default, Xcode creates for use a starting scene that is completely useless for the such of this article. Remove it and open the ViewController.swift file automatically created for us.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-2-480.avif 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-2-960.avif 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-2-1092.avif 1092w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-2-480.webp 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-2-960.webp 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-2-1092.webp 1092w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-2.png&quot; alt=&quot;Xcode dialog asking whether to move art.scnassets to the Trash or only remove the reference&quot; width=&quot;1092&quot; height=&quot;302&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Since we don’t care anymore about the automatically generated scene, we will modify the viewDidLoad method to reflect this behavior. All that we need is to instruct the sceneView outlet with the right delegate instance as well as some funcy stuff for debugging purpouses.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; viewDidLoad&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; super.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;viewDidLoad&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; sceneView.delegate &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; sceneView.showsStatistics &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; sceneView.autoenablesDefaultLighting &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; sceneView.automaticallyUpdatesLighting &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;ARSCNView class is the entry point for any AR app. It mixes virtual contents with the real word seen throught the camera device. It is also responsible for many other really interesting stuff like mapping touches to real world coordinates. ARSCNView relies on a delegate approach. By implementing its ARSCNViewDelegate, we can add virtual contents to any real object that is automagically detected by ARKit.&lt;/p&gt;
&lt;p&gt;As you may guess ARKit is the framework responsible for Augmented Reality. In order to work, it should be correctly initialized first. Let’s add a method to do it:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; resetTrackingConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    guard&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARReferenceImage.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;referenceImages&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;inGroupNamed&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Photos&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, bundle&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; configuration:ARConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; #available&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;iOS&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 12.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ARImageTrackingConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARImageTrackingConfiguration).trackingImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARImageTrackingConfiguration).maximumNumberOfTrackedImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ARWorldTrackingConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARWorldTrackingConfiguration).detectionImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; options: ARSession.RunOptions &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [.resetTracking, .removeExistingAnchors]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    sceneView.session.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;configuration, options&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; options&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The resetTrackingConfiguration method is responsible to create and return a correctly working ARSession instructed by an ARConfiguration.&lt;/p&gt;
&lt;p&gt;ARSession is a singleton shared object that manages the device camera as long as the device motion sensors to give us a full augmented experience of real life. Camera movements are melted down with camera tilt and shift sensors as well as other sensors, in order to give a quick and consistent orientation of the artificial world into the application. ARSCNView instance created for us by storyboard contains already a reference to the default shared ARSession, so we don’t care about initializing it. Instead, we need only to create a valid ARConfiguration.&lt;/p&gt;
&lt;p&gt;ARConfiguration is an abstract class and we don’t deal directly with it. Instead, we will use istances of ARWorldTrackingConfiguration and ARImageTrackingConfiguration that are implementation of the former one. There are other implementations that deals with tracking the device orientation only (AROrientationTrackingConfiguration) and faces and facial expressions (ARFaceTrackingConfiguration) but they are not relevant for this discussion.&lt;/p&gt;
&lt;p&gt;ARWorldTrackingConfiguration is the main class available for World-tracking session. Firstly introduced with iOS11, it can detect and track a lot of interesting elements in our real world, including 3d objects, infinite planes and 2d images. The former one is interesting for our topic; however, iOS12 introduce a brand new specialization for the ARConfiguration abstract class named ARImageTrackingConfiguration.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As its predecessor it is able to track 2d images but with a lot improvements such as real time tracking and automatic handling when the image disappears from view. We will come back to this topic in a few moments.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since we would like to support both iOS11 and iOS12 for a comparative performance, we need to go in deep with custom configurations for both ios versions. If is available iOS12 we will use the new ARConfiguration implementation:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; #available&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;iOS&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 12.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ARImageTrackingConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARImageTrackingConfiguration).trackingImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARImageTrackingConfiguration).maximumNumberOfTrackedImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;otherwise we will use the standard one:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ARWorldTrackingConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARWorldTrackingConfiguration).detectionImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;in both cases we will instruct the shared session to use the crafted configuration for the rest of the discussion:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; options: ARSession.RunOptions &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [.resetTracking, .removeExistingAnchors]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;sceneView.session.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;configuration, options&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; options&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now that we have correctly configured the ARSession, we need some images to use against the ARCamera tracking engine. Select the Assets onto your project:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-3-480.avif 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-3-541.avif 541w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-3-480.webp 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-3-541.webp 541w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-3.jpg&quot; alt=&quot;Xcode project navigator showing the ARWorld project with Assets.xcassets selected&quot; width=&quot;541&quot; height=&quot;679&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;and right click on the left side, creating a new AR Resource Group:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-4-480.avif 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-4-960.avif 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-4-1025.avif 1025w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-4-480.webp 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-4-960.webp 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-4-1025.webp 1025w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-4.png&quot; alt=&quot;Asset catalog context menu with New AR Resource Group highlighted&quot; width=&quot;1025&quot; height=&quot;473&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Name it Photos and add some cards to it. Here the most important thing is to add the relative estimated dimensions for each card. It is important since the 3d engine need this information to estimate correctly the object in the 3d world.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-5-480.avif 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-5-960.avif 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-5-1294.avif 1294w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-5-480.webp 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-5-960.webp 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-5-1294.webp 1294w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-5.png&quot; alt=&quot;AR Resource Group with two reference images, card1 and card2, and the size fields of card1 expressed in meters&quot; width=&quot;1294&quot; height=&quot;447&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;As you may notice one of the card has a warning signal. Let click on it:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-6-480.avif 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-6-960.avif 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-6-1156.avif 1156w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-6-480.webp 480w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-6-960.webp 960w, https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-6-1156.webp 1156w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/arkit2-image-tracking-performance/fig-6.png&quot; alt=&quot;Xcode warning for card2: the histogram is narrow and the image has low local contrast&quot; width=&quot;1156&quot; height=&quot;574&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Xcode is warning us that the histogram and constrasts on the card is not optimal for image recognition. Lets ignore it for the moment.&lt;/p&gt;
&lt;p&gt;Our toy app should be able to track 2D images and map them to real world objects by using anchors. An ARAnchor is the class responsible for real-world position and orientation, mapping the detected object in an AR scene. Along with other interesting properties it contains a matrix_float4x4 used for defining the anchor’s rotation, translation and scale in world coordinates.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; transform: matrix_float4x4 { &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;When used along side with ARWorldTrackingConfiguration or ARImageTrackingConfiguration, ARKit creates automatically for us the relative anchors as long as a match with our reference images is found in the scene. All we have to do is implemeting the relative delegate, in order to add the corresponding object in the form of SCNNode to the new anchor.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; renderer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; renderer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: SCNSceneRenderer, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;nodeFor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: ARAnchor) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; SCNNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; imageAnchor &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anchor &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARImageAnchor {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; node &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SCNNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        node.name &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anchor.identifier.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;description&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; labelNode:SCNNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        switch&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; imageAnchor.referenceImage.name {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;card1&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            labelNode &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;addLabel&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Hi, Costantino!\nYour loyalties points are 2032.&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; imageAnchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;card2&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            labelNode &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;addLabel&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Last tweet from Costantino:\n#WWDC18 #ARKit2 rocks!&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; imageAnchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        default:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; labelNode &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; labelNode {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            node.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;addChildNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;labelNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            node.opacity &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            DispatchQueue.main.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                node.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;runAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;SCNAction.fadeIn&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;duration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;SCNNode is the basic lego brick for all AR based apps. It wraps together 3d coords with scene objects such as lights, camera and other displayable contents. As for UIViews, SCNNodes follows a tree hierarchy that allow us to nest them in a fancy way by using simple primitives such as&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; addChildNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; child&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: SCNNode)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; removeFromParentNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;renderer:nodeFor: method is called in response to a new detected correspondance between our images dataset and the real world. Since this method is also called in response to any new ARAnchor added to the scene (detected planes, 3d objects and so on) we should test against ARImageAnchor in order to be sure that all things are working right:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; imageAnchor &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anchor &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARImageAnchor {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;   …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;next, we create a new SCNNode that will contain all the relevant stuff and we switch against the detected image name; this is the main business logic in order to distinguish between images from our dataset.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; imageAnchor.referenceImage.name {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; “card1”&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; “card2”&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    default:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;then, if we successfully create a valid node, we add it to the hyerarchy and return the main node:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; labelNode &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; labelNode {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; node.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;addChildNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;labelNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;to give a professional touch, we would like to add some fadein/fadeout animations to the entire workflow. Since the rederer:nodeFor: is called on the main thread we should async the runAction, in order to be sure that no crappy animations will occur.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;DispatchQueue.main.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    node.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;runAction&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;SCNAction.fadeIn&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;duration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;for-the-more-curious&quot;&gt;For the more curious&lt;/h2&gt;
&lt;p&gt;addLabel is a support method used to generate a valid 2D spritekit object. Since we are dealing with 2D tracked images, we would like to add 2d virtual contents on the scene to give the user the feel that additional informations are added just above the real object.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; addLabel&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: ARImageAnchor) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; SCNNode {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; plane &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SCNPlane&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; anchor.referenceImage.physicalSize.width,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                         height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; anchor.referenceImage.physicalSize.height&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; planeNode &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SCNNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;geometry&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; plane&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    planeNode.eulerAngles.x &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;pi&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; skScene &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SKScene&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; sceneSize&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    skScene.backgroundColor &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIColor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;white&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, alpha&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; substrings: [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; text.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;components&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;separatedBy&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;\n&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aSubstring &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; substrings {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lbl &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SKLabelNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; aSubstring&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        lbl.fontSize &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        lbl.numberOfLines &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        lbl.fontColor &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; UIColor.white.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;withAlphaComponent&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;0.85&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        lbl.fontName &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Helvetica-Bold&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CGFloat&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;substrings.index&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; aSubstring&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lbl.fontSize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        lbl.position &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CGPoint&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, y&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        lbl.horizontalAlignmentMode &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .left&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        lbl.yScale &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; -1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        skScene.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;addChild&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;lbl&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; material &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SCNMaterial&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    material.isDoubleSided &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    material.diffuse.contents &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; skScene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    plane.materials &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [material]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; planeNode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We firstly create a SCNPlane with the physycal size of the detected image. SCNPlane is a rectangular 2d plane geometry object responsible to hold our bidimensional text. However, since we are in a 3D world we need to wrap it against an SCNNode.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; planeNode &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SCNNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;geometry&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; plane&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;planeNode.eulerAngles.x &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;pi&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We should also rotate the resulting planeNode since, by default, they are generated perpendicular to the root. At this point no 2d objects nor text are still created. To accomplish this we need to create a SprikeKit Scene.&lt;/p&gt;
&lt;p&gt;SKScene is the counterpart of SCNScene on the 2d world handled by SpriteKit. It represents a 2d scene content and it has nothing to display since, as its 3d paritetic, is merely a wrapper. To generate the 2d text we will use the SKLabelNode. It works quite similar to the UILabel UIKit counterpart: we configure text, font and other parameters in a very straightforward way.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lbl &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SKLabelNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; aSubstring&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lbl.fontSize &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lbl.numberOfLines &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lbl.fontColor &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; UIColor.white.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;withAlphaComponent&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;0.85&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lbl.fontName &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; “Helvetica&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;Bold”&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Sadly, there is no native support for multilines wrapping by using the carriage return (\n) so we need to recreate it by our own. To accomplish this we use a simple string tokenization with the original string as parameter.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; substrings: [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; text.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;components&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;separatedBy&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; “\n”&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aSubstring &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; substrings {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The most interesting part here, is how we map the 2d spritekit in the 3d world. To achive this we use the SCNMaterial. SCNMaterial is a class responsible to define the appearance of a 2d geometry when rendered in a 3d world. As of any 3d engine, our SCNScene has lights and materials that respond to it when rendered. We need simply to specify to our SCNMaterial that we would like to use the content of the previously created SKScene as material.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; material &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SCNMaterial&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;material.isDoubleSided &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;material.diffuse.contents &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; skScene&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;isDoubleSided property is set to false, since we don’t care about the backward side of our text. the diffuse property is a SCNMaterialProperty class. It is simply a container for the texture of our material. Fortunately for us it could contains almost anything including a whole SKScene. At the end we instruct our previously generated plane to use the just crafted custom material as source.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;plane.materials &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [material]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If you have followed all we have done right now and run what we have so far on iOS12, all things will work like a charm and you will be delighted by an impressive and accurate 2d tracking. However, if you run the same code on iOS11 you will be disappointed about poor tracking performances.&lt;/p&gt;
&lt;p&gt;Moreover, there is a really crappy bug that leave the detected 2d images on the 3d world for ever. If you recall, at the very beginning of this article I said that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;one of the most interesting new features of ARImageTrackingConfiguration is related to the new handling capabilities with disappeared objects from the screen.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since we don’t have such things on iOS11 we need to create a workaround by ourself. We will use a private struct to hold all the required information:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SANodeAnchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; date:Date&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; node:SCNNode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anchor:ARAnchor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;declaring it as a private array on our ViewController. We also need a periodic polling of the scene, in order to purge trashed objects&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lastUpdate &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;SANodeAnchor]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; scheduledTimer:Timer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;our viewDidAppear method will be responsible to define the above timer&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;override&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; viewDidAppear&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; animated&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    super.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;viewDidAppear&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;animated&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; #available&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;iOS&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 12.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; scheduledTimer &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; scheduledTimer {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            scheduledTimer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;invalidate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        scheduledTimer &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Timer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;scheduledTimer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;withTimeInterval&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, repeats&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;unowned&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;timer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, nodeStruct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.lastUpdate {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.timeIntervalSinceNow &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; nodeStruct.date.timeIntervalSinceNow &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    nodeStruct.node.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;removeFromParentNode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    self.sceneView.session.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; nodeStruct.anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We only need to refresh the lastUpdate cache array when new or already detected objects are correctly parsed on the scene. For this task, we will use another delegate method of ARSCNViewDelegate:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; renderer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; renderer&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: SCNSceneRenderer, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;didUpdate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; node&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: SCNNode, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: ARAnchor) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; identifier &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; node.name {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aStruct &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; SANodeAnchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, node&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; node, anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; anchor&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        lastUpdate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;identifier&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aStruct&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This way even on iOS11 we can successfully stop tracking unwanted 2d objects from the screen.&lt;/p&gt;
&lt;p&gt;The complete project is available on &lt;a href=&quot;https://github.com/valvoline/ARKit2-trackingImages&quot;&gt;Github&lt;/a&gt;. As I’m writing &lt;a href=&quot;https://stackoverflow.com/questions/50863327/arworldtrackingconfiguration-does-not-work-when-deployed-from-xcode10-to-ios11-d/50864848#50864848&quot;&gt;a bug is afflicting Xcode10&lt;/a&gt; that prevents using dataset images when deploying to iOS11 devices.&lt;/p&gt;
&lt;p&gt;as result, on iOS11 the app will not detect any 2d images when deployed from Xcode10. To workaround this, you should run the above project on Xcode9 when you deploy on iOS11 device, commenting the unknown symbols related to ARImageTrackingConfiguration.&lt;/p&gt;
&lt;h3 id=&quot;loading-remote-datasets&quot;&gt;Loading remote datasets&lt;/h3&gt;
&lt;p&gt;A final note about loading dynamic dataset. The above code rely on a static dataset that we have stored into our dataset. However it could be better to dinamically load the dataset from a remote server. I’ve crafted a really simple JSON example for the purpouse.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Code&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;[
 {
  &amp;quot;imageURL&amp;quot; : &amp;quot;https://www.sofapps.it/card1.jpg&amp;quot;,
  &amp;quot;name&amp;quot; : &amp;quot;card1&amp;quot;,
  &amp;quot;width&amp;quot; : 0.096
 },
 {
  &amp;quot;imageURL&amp;quot; : &amp;quot;https://www.sofapps.it/card2.jpg&amp;quot;,
  &amp;quot;name&amp;quot; : &amp;quot;card2&amp;quot;,
  &amp;quot;width&amp;quot; : 0.058
 }
]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Lets fetch this json from our app:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; loadRemotedataset&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fromURL&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: URL, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; completion&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;@escaping&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ([Card]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    URLSession.shared.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;dataTask&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; fromURL&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { (data, response, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            DispatchQueue.main.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                completion&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; data &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; data {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; retArray &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [Card]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            do&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; json &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; try&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; JSONSerialization.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;jsonObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; data, options&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; .allowFragments&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Any&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;]] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRow &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; json {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aString &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRow&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;imageURL&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anURL &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; aString&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aName &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRow&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; width &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRow&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; CGFloat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            retArray.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;Card&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; anURL, name&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; aName, width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    DispatchQueue.main.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                        completion&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;retArray, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    throw&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; NSError&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;JSON parse error&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, code&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, userInfo&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            catch&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                DispatchQueue.main.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    completion&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;resume&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;and load the cards dinamically:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; createDataset&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; completion&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;@escaping&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ([ARReferenceImage]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;loadRemotedataset&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fromURL&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;https://www.sofapps.it/sampleDataset.json&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { (response, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;something happened in the way to heaven...&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            completion&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; response &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; response {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; retArray &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [ARReferenceImage]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aCard &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; response {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; response &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; URLSession.shared.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;synchronousDataTask&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; aCard.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; response.2 {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;something happened in the way to heaven...&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; data &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; response.0, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anImage &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIImage&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; orientation &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; CGImagePropertyOrientation.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    switch&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anImage.imageOrientation {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;up&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        orientation &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;down&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        orientation &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;down&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .left&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        orientation &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .left&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .right&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        orientation &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .right&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    default:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        orientation &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; cgImage &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anImage.cgImage {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                        let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aReferenceImage &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARReferenceImage.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;cgImage, orientation&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; orientation, physicalWidth&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; aCard.width&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        aReferenceImage.name &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aCard.name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        retArray.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aReferenceImage&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            completion&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;retArray, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;our resetTrackingConfiguration method should also be adapted to take into account the loading at runtime:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; resetTrackingConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;createDataset&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;weak&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;referenceImages, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;oops!, something happened on the way to heaven...&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; configuration:ARConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; #available&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;iOS&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 12.0&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ARImageTrackingConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARImageTrackingConfiguration).trackingImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARImageTrackingConfiguration).maximumNumberOfTrackedImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; referenceImages.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            } &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ARWorldTrackingConfiguration&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                (configuration &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ARWorldTrackingConfiguration).detectionImages &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Set&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;referenceImages.map { $0 }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; options: ARSession.RunOptions &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [.resetTracking, .removeExistingAnchors]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            self&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.sceneView.session.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;configuration, options&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; options&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;At this point the app should work on both iOS11 and iOS12, loading dinamically the dataset content from the server.&lt;/p&gt;
&lt;p&gt;-Happy coding!&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/arkit/&quot;&gt;ARKit Official Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/arkit&quot;&gt;ARKit Developer Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/arkit/handling_3d_interaction_and_ui_controls_in_augmented_reality&quot;&gt;ARKit Handling 3D interaction and UI Controls&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Custom CloudKit sharing workflow</title>
    <link href="https://www.sofapps.it/blog/custom-cloudkit-sharing/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/custom-cloudkit-sharing/</id>
    <published>2018-06-02T00:00:00Z</published>
    <updated>2018-06-02T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="Swift"/>
    <category term="UIKit"/>
    <category term="Tutorial"/>
    <category term="CloudKit"/>
    <category term="WWDC18"/>
    <summary>The default CKShare flow needs a UICloudSharingController, a link sent through a third party app and delegates on the receiving side. This post keeps the CKShare URL in the privateShareUrl field of a public record, so the owner adds participants silently and they fetch the private record through the shared database. It includes the Swift code for the zone, the records, the share and the fetch, and a sample project on GitHub.</summary>
    <content type="html">&lt;p&gt;CloudKit has a strong emphasis on users privacy and security. Since one of the main concern for my last work - Lookii - was about users privacy, it was a good chance to investigate in deep about the real potential of the framework.&lt;/p&gt;
&lt;p&gt;As of iOS10, CloudKit comes with a built-in feature related to sharing private data among participants on a container, namely CKShare. Unfortunately, there are very few articles about this topic on the internet and Apple documentation does not go in deep with advanced topics. All the relevant articles that I cited in the footnotes cover the basic flow of CloudKit sharing with some interesting variants that, however, didn’t fit exactly my case. I will not cover the basics, for that I will remand to the footnotes. Instead, I will focus on a specific and more advanced workflow that would be useful for someone else.&lt;/p&gt;
&lt;h3 id=&quot;the-use-case&quot;&gt;The use case&lt;/h3&gt;
&lt;p&gt;Suppose that you have an application that shares users information. Some of those need to be private and shared only among friends, while others should be publicly accessible from every participants in the container.&lt;/p&gt;
&lt;p&gt;Let’s suppose that our CKRecord type is MyUser containing the following public information:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;firstName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;lastName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;thumbnail&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;privateShareUrl&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;some others data will not be flagged as public due to privacy concerns. For these we will use another CKRecord that we will call PrivateInfo, containing the following:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;phoneNumber&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This time, the record will not be part of public database. Instead, it will be saved on the private one — accessible exclusively from the owner of the record— and marked as part of a RecordZone that will be shared with selected participants.&lt;/p&gt;
&lt;p&gt;A general scheme for the described use case could be something as follow:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/custom-cloudkit-sharing/fig-1-480.avif 480w, https://www.sofapps.it/blog/custom-cloudkit-sharing/fig-1-960.avif 960w, https://www.sofapps.it/blog/custom-cloudkit-sharing/fig-1-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/custom-cloudkit-sharing/fig-1-480.webp 480w, https://www.sofapps.it/blog/custom-cloudkit-sharing/fig-1-960.webp 960w, https://www.sofapps.it/blog/custom-cloudkit-sharing/fig-1-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/custom-cloudkit-sharing/fig-1.png&quot; alt=&quot;Diagram: the public database with firstName, lastName, thumbnail and privateShareUrl, the private database with phoneNumber and email, and between them the shared zone FavZone&quot; width=&quot;1400&quot; height=&quot;569&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;h2 id=&quot;cloudkit-general-workflow-and-limitations&quot;&gt;CloudKit general workflow and limitations&lt;/h2&gt;
&lt;p&gt;As stated above, one of the main concern in using CloudKit sharing default workflow was related to the very basic UI customization options. Specifically, the basic workflow uses a very rigid schema:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Who share should be in charge of:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Create the CKShare&lt;/li&gt;
&lt;li&gt;Pass it to a specific UICloudSharingController&lt;/li&gt;
&lt;li&gt;Create a URL to share using third party apps&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Users that want to be added need to:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Click on the link for accepting the shared url&lt;/li&gt;
&lt;li&gt;Implement some delegates on the UIApplication&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even if its straightforwardness makes it super easy to integrate, this approach lacks some advanced features. For example, I wouldn’t bother users with complicated flows that interrupt the natural experience of the app. Instead, I would like to run the workflow much as in the background, freeing source and destination from useless dialogs and app context switching.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It would be great, if I could select receivers of my private information by simple tapping the users icon in my app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;
&lt;p&gt;The first thing that we need to do is enabling userDiscoverability among app users, otherwise the rest of the process will not work due to privacy constraints.&lt;/p&gt;
&lt;p&gt;Thanks god, Apple designed a very easy approach for this task and it requires only a simple access to user permission that you can manage to add in the early stage of your app:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;//ask for userDiscoverability otherwise you will obtain nil each time you try to search for him&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;CKContainer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;requestApplicationPermission&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;CKApplicationPermissions.userDiscoverability&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { (status, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    switch&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; status {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .granted&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;granted&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .denied&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;denied&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .initialState&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;initial state&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .couldNotComplete&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;an error as occurred: &quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;??&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Unknown error&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Once the user granted his permission we are ready to go. Let’s create a very basic user CKRecord (the one that will be public):&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; createPublicRecord&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRecord &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecord&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;recordType&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;MyUser&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    aRecord.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;setObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordValue, forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;firstName&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    aRecord.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;setObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;Appleseed&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordValue, forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;lastName&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; CKContainer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; publicDatabase &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container.publicCloudDatabase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    publicDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aRecord, completionHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; { (record, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;record saved successfully&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Next, as part of the initial process, we need to create a specific zone that we will use to expose a view of our private records to selected users (our favorite friends):&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; createFavZone&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;completionHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;@escaping&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (CKRecordZone&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; CKContainer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; privateDatabase &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container.privateCloudDatabase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; customZone &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordZone&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;zoneName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;FavZone&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    privateDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;customZone, completionHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ({returnRecord, error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        completionHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;returnRecord, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    })&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Finally, we will create a private record containing all our valuable information:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; createPrivateRecord&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; CKContainer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; privateDatabase &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container.privateCloudDatabase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; recordZone: CKRecordZone &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordZone&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;zoneName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;FavZone&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRecord &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecord&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;recordType&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;PrivateInfo&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, zoneID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; recordZone.zoneID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    aRecord.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;setObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;+393331112223&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordValue, forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;phoneNumber&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    aRecord.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;setObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;john@appleseed.com&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordValue, forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;email&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    privateDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;aRecord, completionHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; { (record, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;record saved successfully&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Note that the record is tied to the CKRecordZone created early.&lt;/p&gt;
&lt;p&gt;As you could point out, we still haven’t written the privateShareUrl field that is part of the public record; this is the crucial part of the whole approach described in this article. The standard behaviour, in fact, is based on the UICloudSharingController that will prompt the user with a dialog containing what and how to share the information. The result of the dialog is an URL that we need to use with third party apps such as Message, Email or whatever in order to communicate our intention to share something.&lt;/p&gt;
&lt;p&gt;To make things even worst, on the other side, the receiver needs to click the link that, in turn, will open our app calling a corresponding UIApplocation delegate method. The latter, at the end, will give us a CKShareMetadata instance that we can use to fetch shared information.&lt;/p&gt;
&lt;h2 id=&quot;our-approach&quot;&gt;Our approach&lt;/h2&gt;
&lt;p&gt;Since our application already contains users, I would like to bypass this workflow by using the privateShareUrl field as an entry point for everyone that needs to fetch private information from a specific user.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Apple states that the share url for CKShare is stable and will not change unless you change the root record associated with it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My plan is to simulate the basic sharing workflow by using the privateShareUrl field that we have on the public database for each user. This field will contain the original CKShare url. This way, every user that would like to fetch private information from a specific participant will access the url and check if he/she have access permission to the private fields exposed.&lt;/p&gt;
&lt;p&gt;On the other hand, users that would like to share their private info with friends can simply add them to the share url, without bothering the receivers with third party apps and messages. Sounds great!&lt;/p&gt;
&lt;p&gt;The first thing that we have to do is to create a default none access to our private information. This way, in the initial state no one can access our private data. Only when we add someone to the share, he would be able to access data. Apple, states that the default CKShare public permission is already configured for none access.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; createDefaultShareProfileURL&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; CKContainer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; privateDatabase &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container.privateCloudDatabase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; query &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKQuery&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;recordType&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;PrivateInfo&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, predicate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; NSPredicate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;TRUEPREDICATE&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, argumentArray&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; recordZone: CKRecordZone &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordZone&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;zoneName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;FavZone&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    privateDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;query, inZoneWith&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; recordZone.zoneID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { (results, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; results &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; results, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; ourRecord &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; results.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;first&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; share &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKShare&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;rootRecord&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; ourRecord&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; modOp: CKModifyRecordsOperation &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKModifyRecordsOperation&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;recordsToSave&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; [ourRecord, share], recordIDsToDelete&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            modOp.savePolicy &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .ifServerRecordUnchanged&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            modOp.modifyRecordsCompletionBlock &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { records, recordIDs, error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                    print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;error in modifying the records: &quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anURL &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; share.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; CKContainer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; publicDatabase &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container.publicCloudDatabase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; query &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKQuery&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;recordType&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;MyUser&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, predicate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; NSPredicate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;TRUEPREDICATE&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, argumentArray&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; myPublicProfile:CKRecord&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    publicDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;query, inZoneWith&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { (results, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;error: &quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; results &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; results {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                            for&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRecord &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; results {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRecord.creatorUserRecordID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;.recordName &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;__defaultOwner__&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                                    myPublicProfile &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; aRecord&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                    break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; myPublicProfile &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; myPublicProfile {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            myPublicProfile.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;setObject&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;anURL.absoluteString &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordValue, forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;privateShareUrl&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            publicDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;myPublicProfile, completionHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; { (record, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                    print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;error: &quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                    print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;all done, folks!&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                            }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            privateDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;modOp&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, every time an user would like to see private info shared by someone else will check the deisgnated privateShareUrl for the pertinent user:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; refreshUserInformation&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-parameter)&quot;&gt; userRecordID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;: CKRecordID) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; CKContainer.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; publicDatabase &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container.publicCloudDatabase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    publicDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;withRecordID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; userRecordID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { (record, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; record &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; record {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; firstName &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; record.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;firstName&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; lastName &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; record.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;lastName&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;            //do something with firstName and lastName, updating UI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; shareURL &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; record.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;privateShareUrl&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; sharedDatabase &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; container.sharedCloudDatabase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; anURL &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; shareURL&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; op &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKFetchShareMetadataOperation&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;shareURLs&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; [anURL]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                op.perShareMetadataBlock &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { shareURL, shareMetadata, error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                        print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; shareMetadata &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; shareMetadata {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; shareMetadata.participantStatus &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .accepted {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; query &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKQuery&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;recordType&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;PrivateInfo&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, predicate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; NSPredicate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;TRUEPREDICATE&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, argumentArray&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; zone &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordZoneID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;zoneName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;FavZone&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, ownerName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; (shareMetadata.ownerIdentity.userRecordID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.recordName)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            sharedDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;query, inZoneWith&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; zone, completionHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; { (records, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                    print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; records &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; records, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; firstRecord &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; records.first {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; phoneNumber &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; firstRecord.object&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;phoneNumber&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; email &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; firstRecord.object&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;email&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;                                    //do something with private infos&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                            }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; shareMetadata.participantStatus &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .pending {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; acceptOp &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKAcceptSharesOperation&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;shareMetadatas&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; [shareMetadata]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            acceptOp.qualityOfService &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; .userInteractive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            acceptOp.perShareCompletionBlock &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { meta, share, error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                    print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; share &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; share {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; query &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKQuery&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;recordType&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;PrivateInfo&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, predicate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; NSPredicate&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;TRUEPREDICATE&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, argumentArray&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                    let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; zone &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; CKRecordZoneID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;zoneName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;FavZone&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, ownerName&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; (share.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;owner&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.userIdentity.userRecordID&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.recordName)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                                    sharedDatabase.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;perform&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;query, inZoneWith&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; zone, completionHandler&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; { (records, error) &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                        if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                            print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                        else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; records &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; records, &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; firstRecord &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; records.first {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; phoneNumber &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; firstRecord.object&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;phoneNumber&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                                            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; email &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; firstRecord.object&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;forKey&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;email&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; as?&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;                                            //do something with private infos&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                                    }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                            container.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;acceptOp&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                op.fetchShareMetadataCompletionBlock &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; { error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;                    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; error {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;                        print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;                container.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;op&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Simple and effective. I have assembled a toy application with a complete use-case, available on &lt;a href=&quot;https://github.com/valvoline/CKShareTest&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;-Happy Coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Stored properties and extensions: a pure Swift approach</title>
    <link href="https://www.sofapps.it/blog/swift-stored-properties-extensions/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/swift-stored-properties-extensions/</id>
    <published>2018-03-28T00:00:00Z</published>
    <updated>2018-03-28T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="Swift"/>
    <category term="UIKit"/>
    <category term="Tutorial"/>
    <summary>Swift extensions cannot contain stored properties, and the naive computed property that returns itself loops until the heap is saturated. The post shows a pure Swift workaround that stores values in a static dictionary behind a computed property, instead of the Objective-C associated objects runtime. Two updates fix the shared value between instances by keying the dictionary per instance, first by debugDescription and then by memory address.</summary>
    <content type="html">&lt;p&gt;One of the most common question regarding swift extensions is about stored properties. How many times have you wished a stored property within your last-super-cool extension in order to parametizer some behaviours?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As you may know Swift does not allow stored properties into extensions. That’s by design: “Extensions may not contain stored properties.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The most common error is try to overcome the above by implementing something as follow:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;extension&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIViewController&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; myStoredProperty:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        get&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; self.myStoredProperty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        set&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;newValue&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            self.myStoredProperty &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; newValue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Even the above code will compile with no errors, you will realize sooner that it is completely wrong; in fact, the cycling reference to the computed property will loop your code until the heap will be saturated by almost identical calls.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-1-300.avif 300w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-1-300.webp 300w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-1.jpg&quot; alt=&quot;Cartoon of a thoughtful face with a hand on the chin&quot; width=&quot;300&quot; height=&quot;300&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;The second common approach is googling around. You will stumble across some nifty workarounds in order to add something that resemble the stored properties concept to use inside extensions (see References).&lt;/p&gt;
&lt;p&gt;One of the most (ab)used workaround consist of relying into Objective-C runtime, by adopting a solution based on objc_getAssociatedObject and objc_setAssociatedObject functions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Even if there is nothing wrong in these solutions it would be much more elegant a pure swift approach. That’s the reason about this post: attempting to create a pure swift extension with support for stored properties.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The proposed solution is very simple. It is based on the assumption that extensions don’t accept stored properties but computed ones. By elaborating and digging around the by-value Structs concept, we eventually hack the extensions design adding, in fact, the concept of stored properties. Completely in Swift.&lt;/p&gt;
&lt;p&gt;A proof-of-concept is a lot more useful than thousands of words. So here we go:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIKit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;extension&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIViewController&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Holder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        static&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; _myComputedProperty:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; myComputedProperty:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        get&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Holder._myComputedProperty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        set&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;newValue&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            Holder._myComputedProperty &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; newValue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The Holder struct will contain the private value that our computed property will expose to the world, giving the illusion of a stored property behaviour instead.&lt;/p&gt;
&lt;h2 id=&quot;29-03-update&quot;&gt;29/03 — Update&lt;/h2&gt;
&lt;p&gt;As outlined by Paolo, even if the above approach is working, it should be reviewed at least in two parts in order to solve the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Private scoping&lt;/strong&gt; for the Holder struct (actually, everyone can access the service static Structs changing the value without further controls).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Multiple instances&lt;/strong&gt; of the extended class. The proposed approach suffer of a very nasty problem: if you create multiple instances of the extended class, every instance will share the same static value from the Holder struct. The problem is related to the nature of the static keyword: Every instance of the extended class will share the same static value from the Holder struct. We can use a little bit of imagination in order to be creative and solve the issue.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-2-480.avif 480w, https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-2-640.avif 640w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-2-480.webp 480w, https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-2-640.webp 640w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-2.jpg&quot; alt=&quot;Four panel comic: someone says that human imagination is infinite, is asked to think of a new color, and ends up distraught at a table with empty bottles&quot; width=&quot;640&quot; height=&quot;492&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;The following should do the trick:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;extension&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIViewController&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; Holder&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        static&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; _myComputedProperty &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; myComputedProperty:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        get&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; Holder._myComputedProperty&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;debugDescription&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ??&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        set&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;newValue&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            Holder._myComputedProperty&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;self.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;debugDescription&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; newValue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Here, we exploited some sort of hash table in order to hold all the possible different values belonging to different class instances. Please note that self.debugDescription is a really “raw” approach and we should elaborate a more concise and smart way to distinguish between different references of different classes. But, in any case, it seems working as a poc.&lt;/p&gt;
&lt;h2 id=&quot;30-03-update&quot;&gt;30/03 — Update&lt;/h2&gt;
&lt;p&gt;I couldn’t imagine that there was a so huge interest on this topic! Many thanks to all. There is still a margin of improvement in this approach and after a very kindly discussion with my friend Davide, I decided to give a follow up to the article in order to include some of his suggestions as well as to improve the hash table. Since we use a static var to emulate an hash table, there is no reason to still rely on the Struct approach. Agree. Definitely, this will save a lot of lines of code. Also, I would like to improve the hash table key mechanism by using memory address like pointers. The new version of the approach is as follow:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;extension&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; UIViewController&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; _myComputedProperty &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; myComputedProperty:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;Bool&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        get&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; tmpAddress &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;%p&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, unsafeBitCast&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;self, to&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; UIViewController._myComputedProperty&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;tmpAddress&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; ??&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        set&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;newValue&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;            let&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; tmpAddress &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;%p&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;, unsafeBitCast&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;self, to&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; Int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;            UIViewController._myComputedProperty&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;tmpAddress&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; newValue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-3-300.avif 300w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-3-300.webp 300w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/swift-stored-properties-extensions/fig-3.jpg&quot; alt=&quot;Trollface meme with a wide grin&quot; width=&quot;300&quot; height=&quot;300&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Much, much better! …there is still a minor issue regarding “memory leaking”…but this is another story…&lt;/p&gt;
&lt;p&gt;--Happy swifty coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building a HomeKit accessory</title>
    <link href="https://www.sofapps.it/blog/homekit-accessory-arduino/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/blog/homekit-accessory-arduino/</id>
    <published>2018-02-01T00:00:00Z</published>
    <updated>2018-02-01T00:00:00Z</updated>
    <author><name>Costantino Pistagna</name></author>
    <category term="Arduino"/>
    <category term="C"/>
    <category term="Tutorial"/>
    <category term="HomeKit"/>
    <summary>The article builds a HomeKit gateway with Homebridge on a Raspberry Pi 3 and a hub based on an Arduino YUN that exposes two HTTP endpoints. An NPN transistor wired to a 433MHz RF remote opens an automatic gate, while a DHT22 sensor reports temperature and humidity. Once Homebridge's config.json is set up and the bridge is added in the Home app, everything can be controlled with Siri.</summary>
    <content type="html">&lt;p&gt;This article is meant as a short introductory guide to building a HomeKit compatible accessory using reused, open source components. If you follow all the steps correctly, by the end you will have a remote control for your automatic home gate that you can operate with Siri / HomeKit. As a bonus, you can add an ambient humidity/temperature sensor.&lt;/p&gt;
&lt;p&gt;Ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1x Raspberry Pi 3&lt;/li&gt;
&lt;li&gt;1x Arduino YUN (optional)&lt;/li&gt;
&lt;li&gt;1x 433MHz RF remote for an automatic gate&lt;/li&gt;
&lt;li&gt;1x NPN transistor&lt;/li&gt;
&lt;li&gt;1x 2.2k resistor&lt;/li&gt;
&lt;li&gt;1x A few wires&lt;/li&gt;
&lt;li&gt;1x DHT22 (optional)&lt;/li&gt;
&lt;li&gt;5x Patience&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;HomeKit is the Apple protocol that developers and companies making home automation hardware must adopt if they want to be compatible with the Siri voice assistant and the Home app installed by default on every new iOS device.&lt;/p&gt;
&lt;p&gt;HomeKit is a protocol, that is, a set of rules and specifications that services must follow to be integrated quickly and easily with Apple devices. The protocol (in its non-profit developer version) can be downloaded and studied freely, provided you first accept the attached Apple license. For more information, go here:&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;link-card&quot; href=&quot;https://developer.apple.com/support/homekit-accessory-protocol&quot;&gt;&lt;span class=&quot;link-card-host&quot;&gt;developer.apple.com&lt;/span&gt;&lt;strong&gt;Apple Developer documentation&lt;/strong&gt;&lt;span&gt;Using the HomeKit Accessory Protocol Specification&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Conceptually, to build something that works (and is useful) with HomeKit you need two macro components that talk to each other:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bridge or gateway that speaks the HomeKit protocol and converts all our analog and digital input / output signals into characteristics exposed to the HAP protocol.&lt;/li&gt;
&lt;li&gt;One or more accessories able to talk to the server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Typically, accessories are very simple, elementary objects (light bulbs, switches, temperature sensors, etc.). For reasons of cost and compactness, it is hard to implement on them the logic needed to talk to the server as well.&lt;/p&gt;
&lt;p&gt;The most common solution, adopted by most manufacturers, is to add one more layer of indirection, called a HUB, that &amp;quot;collects&amp;quot; several elementary devices under a single collector, which then has the logic needed to talk to the server; IKEA's and Philips's smart living lines work on this principle. As a result, accessories are lighter and cheaper, at the price of one more object in the chain. That is not a big complication or problem, considering that it noticeably lowers the overall cost of the final objects.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-1-480.avif 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-1-960.avif 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-1-1200.avif 1200w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-1-480.webp 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-1-960.webp 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-1-1200.webp 1200w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-1.png&quot; alt=&quot;Diagram of a gateway connected to a hub, which in turn connects to three accessories, with the coverage area of each on the left&quot; width=&quot;1200&quot; height=&quot;800&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Fortunately, for the gateway there has been a stable and modular open implementation for some time. It is based on node and implements all the features and specifications the HAP protocol requires to build a gateway for HomeKit accessories.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;link-card&quot; href=&quot;https://github.com/homebridge/homebridge&quot;&gt;&lt;span class=&quot;link-card-host&quot;&gt;github.com&lt;/span&gt;&lt;strong&gt;GitHub Homebridge&lt;/strong&gt;&lt;span&gt;Homebridge is a lightweight NodeJS server you can run on your home network that emulates the iOS HomeKit API.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;How it works is very simple. A configuration file declares the accessories supported by the gateway. These accessories are nothing more than software plugins, each representing a particular exposed characteristic. The configuration file is a plain JSON file and the accessories are JSON objects belonging to an array. Some parameters of each accessory are mandatory, others are optional and depend on the specific implementation, since they are initialization parameters.&lt;/p&gt;
&lt;h2 id=&quot;implementation-gateway&quot;&gt;Implementation: Gateway&lt;/h2&gt;
&lt;p&gt;First we will set up our gateway. For this I decided to use a Raspberry Pi 3 on which I had previously installed Raspbian JESSIE:&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;link-card&quot; href=&quot;https://www.raspberrypi.org/downloads/raspbian/&quot;&gt;&lt;span class=&quot;link-card-host&quot;&gt;raspberrypi.org&lt;/span&gt;&lt;strong&gt;Operating system images: Raspberry Pi&lt;/strong&gt;&lt;span&gt;The Raspberry Pi is a tiny and affordable computer that you can use to learn programming through fun, practical projects. Join the global Raspberry Pi community.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To install homebridge, just follow the instructions on the project's GitHub page. I ran into no difficulty.&lt;/p&gt;
&lt;p&gt;Once the installation is complete, we can launch our gateway with the homebridge command. On first start, the server warns us that no accessories are configured, so the gateway is not very useful yet.&lt;/p&gt;
&lt;p&gt;There is a very active community on npm and you can find a plugin for almost any need you can imagine. In our case we will build an accessory to open an automatic gate, that is, to drive a &amp;quot;stateless&amp;quot; switch of an RF remote. If we want, we will also add a humidity and temperature sensor that gives us useful information (at practically zero cost) in the room where we place our HomeKit hub.&lt;/p&gt;
&lt;p&gt;Before building our sensors and configuring our HUB, we need to complete the gateway setup by adding two modules that can talk properly to the sensors described above:&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;link-card&quot; href=&quot;https://www.npmjs.com/package/homebridge-http-temperature-humidity&quot;&gt;&lt;span class=&quot;link-card-host&quot;&gt;npmjs.com&lt;/span&gt;&lt;strong&gt;homebridge-http-temperature-humidity&lt;/strong&gt;&lt;span&gt;Supports https devices on HomeBridge Platform.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;link-card&quot; href=&quot;https://www.npmjs.com/package/homebridge-http-switch&quot;&gt;&lt;span class=&quot;link-card-host&quot;&gt;npmjs.com&lt;/span&gt;&lt;strong&gt;homebridge-http-switch Plugin&lt;/strong&gt;&lt;span&gt;homebridge-http-switch is a Homebridge plugin with which you can configure HomeKit switches which forward any requests to a defined http server.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;once installed, they are available right away. We only need to configure homebridge's config.json file accordingly.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  &quot;bridge&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Home1bridge&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    &quot;username&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;CD:32:D2:E1:CC:33&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    &quot;port&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 50800&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    &quot;pin&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;031-43-153&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  &quot;description&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;This is an example configuration file.&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  &quot;accessories&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;accessory&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;HttpTemphum&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Soggiorno&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;url&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;http://yuji.local/arduino/temp&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;httpMethod&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;GET&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;humidity&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;cacheExpiration&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;accessory&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;HTTP-SWITCH&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;Cancello&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;switchType&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;stateless&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      &quot;onUrl&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;http://yuji.local/arduino/switchOn&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Apart from trivial parameters such as the name and the room, each module expects to talk to an HTTP address and receive certain responses for the requested operations; we only need to implement this simple logic to complete the job. The gateway takes care of everything else needed to talk correctly with Apple's HAP protocol.&lt;/p&gt;
&lt;h2 id=&quot;implementation-hub-and-sensors&quot;&gt;Implementation: HUB and sensors&lt;/h2&gt;
&lt;p&gt;To build our HUB, which groups the sensors and talks to them, I decided to use an old Arduino YUN that I had bought for another project and left in a drawer. If you prefer, though, you can use the same Raspberry Pi you used to build the gateway. You just need to adapt the concepts I am about to describe.&lt;/p&gt;
&lt;p&gt;Our HUB must implement an HTTP server that answers the endpoints specified in the homebridge configuration file above, returning the values read from our sensors, which are connected to the input/output pins of the Arduino microcontroller.&lt;/p&gt;
&lt;p&gt;Before writing the code for our Arduino, though, let's take a break and enjoy a bit of electronics, building what we need to turn an ordinary RF remote for automatic gates into one driven by Arduino.&lt;/p&gt;
&lt;p&gt;First we need to find the pins of the remote's open button and solder two short pieces of wire to them.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-2-480.avif 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-2-960.avif 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-2-1100.avif 1100w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-2-480.webp 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-2-960.webp 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-2-1100.webp 1100w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-2.png&quot; alt=&quot;Three views of the remote control circuit board: the buttons on the component side and the solder points of the two wires on the back&quot; width=&quot;1100&quot; height=&quot;1468&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Meanwhile we will have placed our N-P-N transistor on a breadboard, suitably configured with a 2.2k resistor on the control line.&lt;/p&gt;
&lt;p&gt;The base of the transistor goes to Arduino pin 7. The emitter goes to one of the wires we just soldered onto the remote. The collector is connected to one end of the remote's button and to Arduino's ground.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-3-480.avif 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-3-960.avif 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-3-1400.avif 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-3-480.webp 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-3-960.webp 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-3-1400.webp 1400w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-3.png&quot; alt=&quot;Wiring diagram with an Arduino YUN, a breadboard holding the NPN transistor and resistor, and the remote circuit board connected by wires&quot; width=&quot;1400&quot; height=&quot;1522&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;This way we create a normally open circuit that closes (effectively pressing the remote's button) only when a pulse above a certain threshold arrives from the digital pin. What remains is to encode all this in a language our microcontroller understands.&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-4-480.avif 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-4-960.avif 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-4-1355.avif 1355w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-4-480.webp 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-4-960.webp 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-4-1355.webp 1355w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-4.png&quot; alt=&quot;Photo of the real setup: an Arduino YUN, a breadboard with the transistor and the remote's circuit board joined by colored wires&quot; width=&quot;1355&quot; height=&quot;800&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;Arduino YUN is a very interesting hybrid platform made of a Linux server, a WiFi module and an AT microcontroller (very similar to the one used on the Arduino Uno). Arduino's strength, compared to other competitors, is being absolutely simple and effective at handling analog/digital input/output, with a programming language based on C that is quick to learn. To energize our pin 7 above, a few lines of code are enough:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;C++&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;digitalWrite&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; HIGH);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2000&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;); &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;digitalWrite&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; LOW);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;to the above we need to add the logic for the HTTP server. Arduino YUN already includes a mini HTTP server/client platform, exposed very simply through two library objects called ClientBridge and ServerBridge. The server bridge listens for requests coming from the outside world and the client is used to write our replies to whoever called us.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;C++&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;  A simple HomeBridgeHub example for HomeBridge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;  Author: Costantino Pistagna&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &amp;#x3C;dht.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &amp;#x3C;Bridge.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &amp;#x3C;BridgeServer.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &amp;#x3C;BridgeClient.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;dht DHT;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;BridgeServer server;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;String startString;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;#define&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; DHT22_PIN&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;#define&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; REMOTEDOOR_PIN&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; setup&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;  pinMode&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(REMOTEDOOR_PIN&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; OUTPUT);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;  digitalWrite&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(REMOTEDOOR_PIN&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; LOW);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;  Bridge&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;begin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;  server&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;listenOnLocalhost&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;  server&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;begin&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;  Process&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; startTime;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;  startTime&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;runShellCommand&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;date&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  while&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;startTime&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;available&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    char&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; c &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; startTime&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;read&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    startString &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; c;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt; loop&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;  BridgeClient&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; client &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; server&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;accept&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (client) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;    String&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; command &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;readString&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    command&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;trim&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;();       &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-comment)&quot;&gt;//    Console.println(command);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (command &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;temp&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; chk &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; DHT&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;read22&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(DHT22_PIN);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;      switch&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (chk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; DHTLIB_OK&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;        client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{ \&quot;temperature\&quot;:&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;        client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;DHT&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;temperature&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;        client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;, \&quot;humidity\&quot;:&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;        client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;DHT&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;humidity);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;        client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;}&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        break&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; DHTLIB_ERROR_CHECKSUM&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;        client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{ \&quot;status\&quot; : \&quot;Checksum error\&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        break&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; DHTLIB_ERROR_TIMEOUT&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;        client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{ \&quot;status\&quot; : \&quot;Timeout error\&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        break&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;        client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{ \&quot;status\&quot; : \&quot;Unknown error\&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;        break&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (command &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt; &quot;switchOn&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;      client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{\&quot;status\&quot; : \&quot;OK\&quot;}&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;      digitalWrite&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(REMOTEDOOR_PIN&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; HIGH);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;      delay&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2000&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;      digitalWrite&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(REMOTEDOOR_PIN&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; LOW);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;  delay&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;What remains is the temperature sensing. The DHT22 is a digital sensor that is excellent for this purpose: inexpensive and digitally accurate, it needs no calibration and can be used with one of the many available libraries for DHT devices.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;link-card&quot; href=&quot;https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib&quot;&gt;&lt;span class=&quot;link-card-host&quot;&gt;github.com&lt;/span&gt;&lt;strong&gt;DHTlib&lt;/strong&gt;&lt;span&gt;Arduino library for DHT temperature and humidity sensor. AVR optimized&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pin 1 is the power pin&lt;/li&gt;
&lt;li&gt;pin 2 is the pin where data is modulated and serialized&lt;/li&gt;
&lt;li&gt;pin 3 is unused&lt;/li&gt;
&lt;li&gt;pin 4 is ground.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-5-480.avif 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-5-900.avif 900w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-5-480.webp 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-5-900.webp 900w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-5.jpg&quot; alt=&quot;Wiring diagram of a DHT22 sensor on a breadboard connected to an Arduino board for power, ground and data&quot; width=&quot;900&quot; height=&quot;675&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;we will connect pin 2 to pin 4 of our Arduino YUN.&lt;/p&gt;
&lt;p&gt;reading temperature and humidity is also very simple here:&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;C++&lt;/span&gt;&lt;button class=&quot;copy-btn&quot; type=&quot;button&quot; data-copy-code&gt;&lt;svg class=&quot;icon icon--sm&quot; viewBox=&quot;0 0 24 24&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;8&quot; y=&quot;8&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2.5&quot;/&gt;&lt;path d=&quot;M16 8V6.5A2.5 2.5 0 0 0 13.5 4h-7A2.5 2.5 0 0 0 4 6.5v7A2.5 2.5 0 0 0 6.5 16H8&quot;/&gt;&lt;/svg&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;pre&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; chk &lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt; DHT&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;read22&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(DHT22_PIN);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; (chk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; DHTLIB_OK&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{ \&quot;temperature\&quot;:&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;DHT&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;temperature&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;, \&quot;humidity\&quot;:&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;DHT&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;humidity);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;}&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    break&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; DHTLIB_ERROR_CHECKSUM&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{ \&quot;status\&quot; : \&quot;Checksum error\&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    break&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt; DHTLIB_ERROR_TIMEOUT&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{ \&quot;status\&quot; : \&quot;Timeout error\&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    break&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    default&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-constant)&quot;&gt;    client&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-punctuation)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-function)&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-token-string-expression)&quot;&gt;&quot;{ \&quot;status\&quot; : \&quot;Unknown error\&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-token-keyword)&quot;&gt;    break&lt;/span&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:var(--shiki-foreground)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;conclusions-wrapping-it-up&quot;&gt;Conclusions: wrapping it up&lt;/h2&gt;
&lt;p&gt;Good. It is time to put all the pieces together. Once the sketch is running on our Arduino, let's check that all the commands work correctly:&lt;/p&gt;
&lt;p&gt;/temp&lt;/p&gt;
&lt;p&gt;/switchOn&lt;/p&gt;
&lt;p&gt;At this point we just need to start homebridge and configure the Home app by scanning the QR code that appears on screen and following the steps shown by Apple's Home app. In the end we will have something like this on screen:&lt;/p&gt;
&lt;figure&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-6-480.avif 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-6-960.avif 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-6-1067.avif 1067w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-6-480.webp 480w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-6-960.webp 960w, https://www.sofapps.it/blog/homekit-accessory-arduino/fig-6-1067.webp 1067w&quot; sizes=&quot;(min-width: 760px) 720px, 100vw&quot;&gt;&lt;img src=&quot;https://www.sofapps.it/blog/homekit-accessory-arduino/fig-6.png&quot; alt=&quot;The Home app on an iPad showing favorite scenes and accessories, including the gate, the hallway thermostat and the living room sensor&quot; width=&quot;1067&quot; height=&quot;800&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/figure&gt;
&lt;p&gt;and the ability to talk to our beloved device by asking it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What's the temperature at home?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;or:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Open the gate&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;homebridge is a very flexible open platform that lets you talk to Apple's HAP protocol quickly and effectively through small modules and simple HTTP based technologies.&lt;/p&gt;
</content>
  </entry>
</feed>
