<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="it">
  <title>Sofapps · Blog</title>
  <subtitle>Articoli, tutorial e novità sullo sviluppo di app per le piattaforme Apple, in italiano e in inglese.</subtitle>
  <link href="https://www.sofapps.it/it/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://www.sofapps.it/it/blog/" rel="alternate" type="text/html"/>
  <id>https://www.sofapps.it/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: la fine della convergenza nel design mobile</title>
    <link href="https://www.sofapps.it/it/blog/liquid-glass-vs-material-3/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Da iOS 7 e Material Design, Apple e Google si erano avvicinate a linguaggi visivi piatti e simili. Liquid Glass scommette su un futuro sensoriale e spaziale, mentre Material 3 Expressive usa colori audaci, tipografia variabile e animazioni elastiche per il pubblico di oggi. Per gli sviluppatori finisce la neutralità: le strade sono UI nativa con logica condivisa, framework cross adattivi o un approccio brand-first.</summary>
    <content type="html">&lt;p&gt;Il 2025 ha cambiato per sempre l’estetica del mondo mobile. Apple ha svelato &lt;strong&gt;Liquid Glass&lt;/strong&gt;, un meta-materiale digitale che porta trasparenza, rifrazione e dinamismo a iOS, iPadOS e macOS.&lt;/p&gt;
&lt;p&gt;Google ha risposto con &lt;strong&gt;Material 3 Expressive&lt;/strong&gt;, evoluzione del Material You, fatta di colori audaci, tipografia variabile e animazioni elastiche.&lt;/p&gt;
&lt;p&gt;Due visioni che non potrebbero essere più diverse. E che decretano la fine di un’era: quella della convergenza estetica.&lt;/p&gt;
&lt;h3 id=&quot;un-passo-indietro-quando-le-strade-sembravano-vicine&quot;&gt;Un passo indietro: quando le strade sembravano vicine&lt;/h3&gt;
&lt;p&gt;Per comprendere la portata di questa divergenza bisogna tornare indietro di oltre un decennio.&lt;/p&gt;
&lt;p&gt;Con &lt;strong&gt;iOS 7&lt;/strong&gt; (2013), Apple archiviò definitivamente lo &lt;strong&gt;skeuomorfismo&lt;/strong&gt;: addio texture di legno e pelle, spazio a tipografia sottile, superfici piatte e leggere trasparenze.&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;La schermata Orologio internazionale di iOS 7, con caratteri sottili, un pulsante Edit rosso e piatto e un semplice orologio analogico&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;Solo un anno dopo Google presentò &lt;strong&gt;Material Design&lt;/strong&gt;, un linguaggio basato sull’idea della &lt;em&gt;“carta digitale”&lt;/em&gt; capace di muoversi e assumere profondità attraverso ombre ed elevazioni.&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;Un relatore di Google sul palco davanti a una grande slide con la scritta 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;In quel momento le due strade sembravano correre parallele. Minimalismo, chiarezza e motion design erano valori condivisi, e per gli sviluppatori di terze parti appariva finalmente plausibile immaginare un’esperienza cross-platform coerente.&lt;/p&gt;
&lt;h2 id=&quot;l-illusione-della-neutralita&quot;&gt;L’illusione della neutralità&lt;/h2&gt;
&lt;p&gt;La convergenza estetica di quegli anni aveva favorito strumenti come &lt;strong&gt;Flutter&lt;/strong&gt; o &lt;strong&gt;React Native&lt;/strong&gt;, in grado di proporre interfacce simili tra iOS e Android senza apparire fuori luogo.&lt;/p&gt;
&lt;p&gt;Ma l’adozione non fu uniforme: su Android la frammentazione rallentò la diffusione di Material Design, mentre su iOS la rigidità delle guideline accelerò l’allineamento.&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;Due schermate di blocco affiancate: iOS con orologio sottile e slide to unlock, e Android con uno sfondo geometrico colorato&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;h2 id=&quot;liquid-glass-apple-punta-al-futuro-sensoriale&quot;&gt;Liquid Glass: Apple punta al futuro sensoriale&lt;/h2&gt;
&lt;p&gt;Con &lt;strong&gt;Liquid Glass&lt;/strong&gt;, Apple introduce un design che va oltre il minimalismo piatto: superfici tridimensionali, rifrazione della luce, trasparenze dinamiche.&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;Controlli Liquid Glass su una griglia: slider di vetro, un pulsante più, un menu a capsula con tre simboli e una pillola trasparente&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;È un’estetica che guarda chiaramente al futuro dello &lt;strong&gt;spatial computing&lt;/strong&gt; e alla continuità con &lt;strong&gt;visionOS&lt;/strong&gt;, creando un legame diretto tra smartphone, tablet, desktop e 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;Una lente di vetro a forma di capsula sopra uno slider blu, che rifrange la barra sottostante&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;Un design sensoriale e quasi fisico, che scommette sul lungo periodo.&lt;/p&gt;
&lt;h2 id=&quot;material-3-expressive-il-presente-di-google&quot;&gt;Material 3 Expressive: il presente di Google&lt;/h2&gt;
&lt;p&gt;Google, al contrario, evolve il suo linguaggio con &lt;strong&gt;Material 3 Expressive&lt;/strong&gt;, che abbraccia una direzione più immediata e pop.&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;Un motivo di pulsanti arrotondati di Material 3 Expressive in azzurro vivo e lilla, con icone ed etichette come Play, Send e 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;Colore saturo, tipografia variabile, animazioni elastiche: un’estetica che parla alla &lt;strong&gt;Generazione Z&lt;/strong&gt; e che privilegia l’accessibilità e l’impatto visivo sul breve termine.&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;Un editor di email in Material 3 Expressive su toni lilla, con i campi From e To in un carattere condensato e uno arrotondato in grassetto&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;Non il futuro del metaverso o della realtà mista, ma un linguaggio vivo, quotidiano e inclusivo.&lt;/p&gt;
&lt;h2 id=&quot;conseguenze-per-sviluppatori-e-brand&quot;&gt;Conseguenze per sviluppatori e brand&lt;/h2&gt;
&lt;p&gt;Questa divergenza non è un semplice cambio estetico: per chi sviluppa applicazioni segna la fine della neutralità.&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;Un iPhone con il Centro di Controllo in Liquid Glass accanto a un telefono Android con le impostazioni rapide Material in viola&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;Le strade ora sono tre:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI nativa con logica condivisa → massima fedeltà estetica alle linee guida di ciascun sistema.&lt;/li&gt;
&lt;li&gt;Framework cross adattivi → skin e branching per rispettare le differenze di stile.&lt;/li&gt;
&lt;li&gt;Approccio brand-first → sempre più scelto dai grandi player, che impongono un’identità sopra le regole dei sistemi operativi.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In altre parole, la sfida non è più scrivere una sola codebase, ma tradurre un &lt;strong&gt;design system in due dialetti diversi&lt;/strong&gt;, senza perdere coerenza né usabilità.&lt;/p&gt;
&lt;h2 id=&quot;una-nuova-competizione-estetica&quot;&gt;Una nuova competizione estetica&lt;/h2&gt;
&lt;p&gt;Liquid Glass e Material 3 Expressive rappresentano due filosofie opposte:&lt;/p&gt;
&lt;p&gt;Apple scommette sul futuro, con un’interfaccia sensoriale che prepara la strada allo spatial computing.&lt;/p&gt;
&lt;p&gt;Google ottimizza il presente, puntando su accessibilità e vivacità per il pubblico di oggi.&lt;/p&gt;
&lt;p&gt;Per gli utenti significa vivere esperienze sempre più caratterizzate dall’ecosistema scelto.&lt;/p&gt;
&lt;p&gt;Per gli sviluppatori, significa fare scelte precise e inevitabili su come adattarsi o differenziarsi.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Il design, ancora una volta, non è solo estetica ma &lt;strong&gt;strategia competitiva&lt;/strong&gt;.&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;Si apre su YouTube. Non viene caricato nulla finché non fai clic.&lt;/span&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;—
Happy coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>WWDC25: Benvenuto Liquid Glass</title>
    <link href="https://www.sofapps.it/it/blog/wwdc25-liquid-glass/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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, presentato alla WWDC25, unifica iOS, macOS, iPadOS, watchOS, visionOS e tvOS in un unico linguaggio visivo. Il post ripercorre la strada dallo skeuomorfismo del primo iPhone al design flat di iOS 7 e al Material Design, poi sostiene che il vetro è una metafora coerente e leggibile per le interfacce a livelli e per il computing spaziale, come ha spiegato Craig Federighi.</summary>
    <content type="html">&lt;p&gt;Una delle innovazioni più interessanti presentate alla &lt;strong&gt;WWDC25&lt;/strong&gt; è senza dubbio il nuovo design system, unito a una rinnovata esperienza utente e a nuovi paradigmi d’interfaccia.&lt;/p&gt;
&lt;p&gt;Parliamo di &lt;strong&gt;Liquid Glass&lt;/strong&gt;, il nuovo sistema di design introdotto da Apple all’inizio di giugno, che unifica di fatto l’intero parco di sistemi operativi della casa di Cupertino in un unico paradigma visivo. L’obiettivo è assicurare una continuità e una fluidità senza precedenti tra iOS, macOS, iPadOS, watchOS, visionOS e anche tvOS.&lt;/p&gt;
&lt;p&gt;Per comprendere appieno questo cambiamento, è utile fare un passo indietro nel tempo, fino al 2007, quando fu presentato il primo iPhone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gli inizi dello skeuomorfismo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Per dare vita a quel rivoluzionario dispositivo composto quasi interamente da uno schermo touch da circa 3.5”, Steve Jobs e il suo team optarono per un’interfaccia visiva basata sui principi dello skeuomorfismo. Fu una scelta voluta dallo stesso Jobs, convinto che fosse essenziale dare agli utenti la sensazione di interagire con oggetti familiari, ora finalmente “toccabili” con le dita. Lo skeuomorfismo, infatti, utilizza elementi grafici che imitano oggetti reali per risultare immediatamente comprensibili. La calcolatrice sembrava una calcolatrice fisica; il blocco note aveva le righe gialle di un vero taccuino; il calendario imitava un’agenda in pelle. Tutto studiato per rendere l’interazione il più naturale possibile.&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;L'app Calendario di iPad nel 2011, con rilegatura in pelle, bordi di carta strappata e cuciture&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;All’epoca, nessuno aveva mai usato uno smartphone interamente touch: i dispositivi concorrenti, combinavano schermo e tasti fisici in un ibrido sgraziato. Jobs voleva qualcosa di radicalmente diverso e lo skeuomorfismo fu un’idea vincente. I pulsanti sembravano tridimensionali, con ombre e riflessi; tutto invitava al tocco. Niente stilo, niente tastiera fisica: solo tap, swipe e pinch.&lt;/p&gt;
&lt;p&gt;Il termine skeuomorfismo deriva dal greco:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;σκεῦος&lt;/strong&gt; (skeuos) = &lt;em&gt;strumento, contenitore&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;μορφή&lt;/strong&gt; (morphē) = &lt;em&gt;forma&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In pratica: &lt;em&gt;“oggetto che mantiene l’aspetto di un altro oggetto più antico o familiare, pur avendo una funzione diversa e moderna”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Esempi analoghi si trovano anche nel mondo fisico: vasi in ceramica che imitano il metallo, colonne in cemento che ricordano il marmo, bottoni decorativi su giacche che non si aprono, ma richiamano chiusure reali.&lt;/p&gt;
&lt;p&gt;Negli anni ’80, questo concetto fece il suo ingresso anche nel digitale: con l’avvento delle interfacce grafiche, si cercava un linguaggio visivo comprensibile per milioni di nuovi utenti. Apple fu tra le prime ad adottare questa filosofia: le icone a forma di cartella, il cestino, il Finder™ stesso sono esempi precoci di skeumorfismo. Questi elementi evolveranno, all’inizio degli anni 2000, nella celebre interfaccia &lt;strong&gt;AQUA&lt;/strong&gt; di MacOSX.&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;Un desktop di Mac OS X con interfaccia Aqua: una finestra del Finder, iTunes, una calcolatrice, menu traslucidi e un Dock con icone lucide&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;Lo skeumorfismo, quindi, non nasce con l’iPhone, ma trova lì la sua massima espressione. Merito anche di Scott Forstall, sotto la supervisione di Jobs, che tra il 2007 ed il 2009 lo introdusse e ne completò la dimensione in iPhoneOS.&lt;/p&gt;
&lt;p&gt;È opinione diffusa che il successo iniziale dell’iPhone sia stato dovuto, in buona parte, proprio a questa scelta visiva rivoluzionaria. L’interfaccia skeumorfica dominò per sei anni, durante i quali maturò e diventò un punto di riferimento anche per sviluppatori indipendenti, che in quel periodo affollavano l’App Store con applicazioni di altissima qualità.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;L’avvento del minimalismo di Jony Ive&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nel 2013, con iOS7, Apple abbandona lo skeumorfismo e abbraccia un design piatto (flat), minimalista, firmato da Jony Ive. Tutto si fa bidimensionale, essenziale, a tratti persino monotono. L’interfaccia iniziale richiese vari aggiustamenti: contrasti deboli, elementi interattivi poco evidenti e colori troppo accesi. Ci vollero un paio d’anni prima che l’idea maturasse in un linguaggio coerente e apprezzato dagli utenti.&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;Due schermate di iOS 7 affiancate: l'app Note e l'app Calendario in stile flat, con caratteri sottili e sfondi bianchi&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 non fu sola in questo percorso. Il design minimale trovò spazio anche altrove: prima con Microsoft e la sua (breve) avventura nel mobile, poi soprattutto con Google e il suo Material Design, che riprese i concetti di iOS7 e li ampliò. Proprio da Google, Apple riprese — nel tempo — molte idee per evolvere l’interfaccia, culminando con la piena maturità raggiunta in iOS 18, dodici anni dopo.&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;Tre telefoni Android con app Material Design in temi verde acqua, arancione e viola, con card, radio button e un pulsante d'azione fluttuante&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;È tempo di cambiare&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Diciotto anni dopo il debutto dell’iPhone, i dispositivi che abbiamo in tasca sono ormai veri e propri computer, con potenze di calcolo un tempo impensabili. Le interfacce minimali — per quanto arricchite da animazioni e transizioni — risultano oggi (troppo) semplici da gestire per hardware così avanzati.&lt;/p&gt;
&lt;p&gt;Ecco perché la scelta di Apple, oggi, appare più che sensata: sacrificare una piccola parte di potenza per rendere le interfacce più vive, espressive e pronte alla realtà aumentata. È l’inizio di un nuovo ciclo.&lt;/p&gt;
&lt;p&gt;Ma perché questa lunga premessa? Perché Liquid Glass rappresenta una rivoluzione comparabile a quella dello skeumorfismo. Ne riprende i concetti chiave, li rielabora e li incapsula in un nuovo materiale simbolico: &lt;strong&gt;il vetro&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;Controlli Liquid Glass su una griglia: slider di vetro trasparente, un menu con tre opzioni, un pulsante più e capsule di vetro&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;Come ha spiegato Craig Federighi in un’intervista al Wall Street Journal, il vetro è il paradigma perfetto per descrivere un’interfaccia pensata per il computing spaziale e la realtà aumentata, basata sulla sovrapposizione di livelli (layers). Ma per rendere questi strati funzionali, serve un sistema coerente, leggibile e usabile sia su dispositivi touch che non touch.&lt;/p&gt;
&lt;p&gt;Il vetro risponde a queste esigenze: trasparente, riflettente, fluido. Permette di vedere attraverso, ma anche di interagire con ciò che è in primo piano, mantenendo la continuità visiva dell’ambiente circostante.&lt;/p&gt;
&lt;p&gt;Ci vorrà tempo perché questo concetto maturi appieno. Ma una cosa è certa: Apple ha scelto la direzione, e l’ha fatto con coerenza. L’autunno ci mostrerà i primi frutti concreti. Benvenuto, Liquid Glass.&lt;/p&gt;
&lt;p&gt;—
Happy coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Dynamic Island: L'isola che non c'è ed il nuovo iPhone 14 Pro</title>
    <link href="https://www.sofapps.it/it/blog/dynamic-island-iphone-14-pro/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Con iPhone 14 Pro Apple sostituisce il notch con la Dynamic Island, un'area attorno ai sensori che diventa parte dell'interfaccia. L'autore ripercorre la storia del notch dal 2017 di iPhone X, lo paragona alla vicenda dei bumper di iPhone 4 e legge il nuovo design come una riuscita fusione tra hardware e software. Conclude che innovare significa anche trasformare un limite in qualcosa di reale.</summary>
    <content type="html">&lt;p&gt;Un colpo di genio. Una mossa che nessuno si aspettava. Nemmeno i leakers più incalliti erano riusciti a cogliere l'essenza di quel buco magico che si vociferava, fino ad un paio d'ore prima, dovesse prendere una forma digitale non ben identificata.&lt;/p&gt;
&lt;p&gt;Centinaia di parole e minuti spesi a parlarne. I disfattisti erano già pronti ad indicare la fine di Apple, che avrebbe perso il suo brand distintivo: &lt;em&gt;il notch&lt;/em&gt;. Qualcun altro, più colto, si domandava se questa scelta non avesse portato a pericolose asimmetrie e difficoltà cognitive rispetto ai contenuti fruiti a schermo. Qualcun'altro giurava di avere le prove che quel notch sarebbe diventato una &lt;em&gt;&lt;strong&gt;i&lt;/strong&gt;&lt;/em&gt; di iPhone rovesciata in orizzontale.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Una cosa è certa. Nessuno è riuscito a togliere uno strabiliante effetto sorpresa a Tim Cook ed alla sua Apple.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Così, eccoci qui ad ammirare attoniti e senza parole l'ultimo colpo da maestro messo a segno da Apple nel suo evento di ieri 7 settembre 2022: L'isola dinamica o per dirla in inglese che forse rende meglio, la: &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;Animazione della Dynamic Island in alto su un iPhone 14 Pro, con la schermata di blocco che mostra l'ora 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;Un concetto che esprime chiaramente come il disegno di Apple si evolva negli anni secondo un copione preciso e senza mai andare a casaccio.&lt;/p&gt;
&lt;p&gt;Nel 2017 &lt;em&gt;(5 anni fa, ndr.)&lt;/em&gt; Apple annuncia al mondo il suo iPhone X, il primo dispositivo dotato di notch, una tacca posizionata al centro dello schermo in alto e destinata ad ospitare gli ingombranti sensori per il riconoscimento facciale e la telecamera frontale. La scelta è fortemente discussa e balza agli occhi della cronaca IT specializzata con un misto di assensi e dissensi, come sempre, aggiungerei.&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;A sinistra un iPhone X con il notch tenuto in mano davanti a una strada di New York, a destra un fotogramma di uno spot con due uomini che guardano il proprio telefono&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;All'epoca si parlava già di display OLED e l'iPhone X ne era dotato. Abbiamo visto altre 4 revisioni di questo notch passando per Xs, 11, 12 e 13. Nelle ultime revisioni ne è stata ridotta leggermente la dimensione ed in questi 5 anni è diventato un pò parte di noi: un'identità univoca del brand Apple e del dispositivo iPhone. Copiato in innumerevoli tentativi dalla concorrenza, ma mai eguagliato nella sua stupida ed assoluta semplicità.&lt;/p&gt;
&lt;p&gt;Siamo nel 2022 ed i tempi sono maturi per andare oltre. Il display montato a bordo del nuovo iPhone 14 Pro ha un valore di contrasto di picco pari a 2.000.000 : 1 ed una resa dei neri pura come non  mai.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E' il momento, insomma, di rendere creativi quei buchi sullo schermo che continuano a rimanere indispensabili per ospitare i sensori e le telecamere.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;La tecnologia è ora pronta a trasformarsi in magia per dare all'utente la sensazione che quei buchi non siano un impedimento ma, al contrario, una feature per rendere più fluida ed indimenticabile l'esperienza a bordo del nuovo iPhone.&lt;/p&gt;
&lt;p&gt;Mi viene da sorridere perché, anche in questo, trovo un'analogia con la filosofia dell'amato e compianto Steve Jobs che, tramutò un problema hardware a bordo degli iPhone 4 in una killer feature e dando vita al mercato delle cover e dei bumper.&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 sul palco accanto a un bumper rosa per iPhone 4 con il prezzo di 29 dollari&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;Che dire? Il risultato di quest'isola dinamica fa sembrare di colpo tutto vecchio. Qualunque declinazione esistente del notch, sembra di colpo portarci indietro di ben oltre 5 anni dando un senso di vecchio a tutta l'esperienza a contorno.&lt;/p&gt;
&lt;p&gt;Mi viene in mente uno spot Apple a me molto caro che, a mio parere, racchiude perfettamente il processo di ideazione e realizzazione di questo capolavoro di sinergia tra hardware e 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;Si apre su YouTube. Non viene caricato nulla finché non fai clic.&lt;/span&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;C'è uno straparlare sul fatto che la Apple di oggi non sappia più innovare e che non ci sia molto altro da tirare fuori dai nostri smartphone. In parte è vero: siamo al confine di un'isola e, prima o poi, dovremo salpare per cercare altre terre.&lt;/p&gt;
&lt;p&gt;Sapere innovare è anche questo: vedere all'orizzonte qualcosa che non c'è e trasformare questo qualcosa in un'isola reale e tangibile.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>App Tracking Transparency con Combine</title>
    <link href="https://www.sofapps.it/it/blog/app-tracking-transparency-combine/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Da iOS 14.5 un'app deve chiedere il permesso all'utente prima di leggere l'identificatore pubblicitario. Il post incapsula ATTrackingManager e ASIdentifierManager in un ATTrackingHelper che adotta ObservableObject e pubblica stato di autorizzazione e identificatore con @Published, e lo usa da una view SwiftUI. Spiega anche la voce NSUserTrackingUsageDescription in Info.plist.</summary>
    <content type="html">&lt;p&gt;Una delle funzionalità più pubblicizzate di iOS 14.5 è la nuova App Tracking Transparency. In giro ci sono moltissimi articoli che cercano di chiarire le posizioni in gioco in questa decisione di Apple e delle controparti come Facebook. Non voglio addentrarmi nell'aspetto politico della questione. Vorrei invece fare una rapida panoramica di ciò che serve per lavorare con questa novità e di cosa significa dal punto di vista tecnologico.&lt;/p&gt;
&lt;p&gt;App Tracking Transparency si basa su un solo componente software, una classe chiamata &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;Copia&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;Secondo Apple questa classe offre tutto il necessario per chiedere il permesso e ottenere lo stato attuale della richiesta. Collabora con l'Ad framework per identificare gli utenti in forma anonima e consentire di tracciarne abitudini e interessi.&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;Diagramma: ATTrackingManager fornisce l'AuthorizationStatus e ASIdentifierManager fornisce l'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;L'Ad framework ha un'istanza condivisa, disponibile in tutto il sistema, sotto forma di una classe chiamata &lt;code&gt;ASIdentifierManager&lt;/code&gt;. Possiamo ottenerla nel modo classico:&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;Copia&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;Inoltre possiamo leggere l'identificatore anonimo corrente in modo altrettanto semplice:&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;Copia&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;Prima di iOS 14.5 voi &lt;strong&gt;(sviluppatori)&lt;/strong&gt; avevate &lt;em&gt;&lt;strong&gt;sempre&lt;/strong&gt;&lt;/em&gt; la possibilità di ottenere questo identificatore sotto forma di oggetto UUID. L'identificatore è anonimo e coerente in tutto il sistema operativo, e permette di tracciare gli utenti tra app e domini diversi. Questo, ovviamente, può compromettere la privacy se uno o più attori in gioco hanno cattive intenzioni (e, credetemi, di attori malintenzionati ce ne sono tantissimi in giro).&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;Diagramma: ASIdentifierManager.advertisingIdentifier al centro, condiviso con nove app diverse rappresentate da quadrati colorati&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;Da iOS 14.5 bisogna chiedere il consenso dell'utente, &lt;em&gt;&lt;strong&gt;app per app&lt;/strong&gt;&lt;/em&gt;, prima di poter accedere a questo identificatore. Significa che voi &lt;em&gt;&lt;strong&gt;(utenti)&lt;/strong&gt;&lt;/em&gt; potete decidere in ogni momento chi può accedere al vostro identificatore, sia all'installazione dell'app sia, se cambiate idea, dalle Impostazioni. Dal punto di vista dei diritti dell'utente è fantastico, e non è nemmeno discutibile.&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;Impostazioni di iOS, Privacy, Tracking: l'interruttore Allow Apps to Request to Track e un interruttore per l'app AskPermissions, entrambi attivi&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;Il nostro obiettivo di oggi è incapsulare queste classi in un oggetto più comodo, da usare sia con Swift sia con SwiftUI. Per riuscirci useremo alcune funzionalità di base di Combine, in modo da esporre correttamente tutti i pezzi che ci servono.&lt;/p&gt;
&lt;p&gt;Per brevità useremo un approccio SwiftUI puro, ma tutto il codice sarà pronto anche per i progetti Swift standard. Cominciamo creando un progetto SwiftUI.&lt;/p&gt;
&lt;p&gt;La prima cosa da fare è aggiungere la descrizione nel nostro &lt;strong&gt;Info.plist&lt;/strong&gt;, in modo da popolare correttamente il messaggio che vedranno gli utenti. Come con CoreLocation o Photos, dobbiamo descrivere con una frase efficace cosa ci serve e perché chiediamo il consenso al tracking. Per farlo aggiungiamo una nuova chiave &lt;code&gt;NSUserTrackingUsageDescription&lt;/code&gt; e la relativa stringa.&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;Sorgente di Info.plist con la chiave NSUserTrackingUsageDescription e la stringa 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;Quando siamo pronti, possiamo scrivere la classe helper che esporrà alla nostra app gli accessor necessari. L'abbiamo chiamata &lt;code&gt;ATTrackingHelper&lt;/code&gt;. Poiché vogliamo essere &lt;strong&gt;notificati&lt;/strong&gt; a ogni cambiamento di &lt;code&gt;AuthorizationStatus&lt;/code&gt; o di &lt;code&gt;AdvertisingIdentifier&lt;/code&gt;, ereditiamo da &lt;code&gt;ObservableObject&lt;/code&gt; e marchiamo le due proprietà interessate con &lt;code&gt;@Published&lt;/code&gt;. Questo significa che &lt;strong&gt;Combine&lt;/strong&gt;, dietro le quinte, genererà per noi tutto il codice necessario per tracciare i cambiamenti e notificare i subscriber.&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;Diagramma di ATTrackingHelper: AuthorizationStatus e advertisingIdentifier marcati @Published, un metodo requestAuth() tra i due, sopra ATTrackingManager e 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;L'ultimo pezzo che manca per rendere utile questa classe è un metodo &lt;code&gt;requestAuth()&lt;/code&gt;, che interagirà con il framework e popolerà di conseguenza i risultati.&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;Copia&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;È il momento di un Proof-Of-Concept. Con questo approccio basta dichiarare un ObservedObject nella nostra ContentView. Più o meno così:&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;Copia&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;Ora possiamo chiedere il consenso all'utente, la prima volta che eseguiamo l'app, e popolare la uuidString richiesta. Che bel periodo per essere sviluppatori iOS! :-)&lt;/p&gt;
&lt;p&gt;Happy coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>SwiftUI dentro UIKit: collegare due mondi</title>
    <link href="https://www.sofapps.it/it/blog/swiftui-within-uikit/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Un proof of concept nato da una chiacchierata su Clubhouse: invece di migrare un intero progetto, si riscrive in SwiftUI solo il contenuto di una UITableViewCell, ospitato in un UIHostingController. UIKit comunica con la view SwiftUI tramite NotificationCenter e Combine, e lo scrolling resta fluido. L'approccio è decisamente poco elegante, e il codice completo è su GitHub.</summary>
    <content type="html">&lt;p&gt;Ieri sera ho partecipato a una room su Clubhouse molto interessante, in cui si parlava di SwiftUI e di interoperabilità con Swift. Il resto dell'articolo è un proof-of-concept che esplora alcune idee emerse durante la chat con
Dimitri Giani, Stefano Mondino e Andrea Mengoli.&lt;/p&gt;
&lt;p&gt;SwiftUI offre ottime prestazioni e rende semplice costruire anche layout complessi, ma spostare un intero progetto da UIKit a SwiftUI non è sempre fattibile, per molte ragioni (maturità del framework, tempi di consegna, e così via). Allora perché non prendere il meglio dei due mondi?&lt;/p&gt;
&lt;p&gt;Esistono decine di &lt;a href=&quot;https://www.swiftbysundell.com/articles/swiftui-and-uikit-interoperability-part-2/&quot;&gt;tutorial&lt;/a&gt; e &lt;a href=&quot;https://www.avanderlee.com/swiftui/integrating-swiftui-with-uikit/&quot;&gt;articoli&lt;/a&gt; sull'uso di &lt;strong&gt;UIHostingController&lt;/strong&gt; che, ad oggi, sembra l'unica strada percorribile per realizzare quanto detto sopra. Ieri sera però ci siamo concentrati su un punto di vista un po' diverso:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Spostare in SwiftUI solo porzioni di codice molto piccole.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Per esempio, una delle cose più odiate da ogni sviluppatore iOS è dover usare lo Storyboard per disegnare le celle di una &lt;strong&gt;UITableView/UICollectionView&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Non sarebbe bello migrare in SwiftUI solo il contenuto di una UITableViewCell, per migliorare prestazioni, manutenibilità e semplicità, rendendo così a prova di futuro almeno una parte del nostro codice? Era la proposta di
Dimitri Giani.&lt;/p&gt;
&lt;p&gt;Tutti, io compreso, eravamo scettici: UIHostingController sembrava un approccio molto complicato e sovradimensionato per un compito così critico dal punto di vista delle prestazioni (parliamo dei componenti riutilizzabili di una UIScrollView).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Inutile dire che mi sbagliavo. Almeno in un primissimo test, descritto nel resto di questo articolo, l'approccio funziona benissimo, con qualche accorgimento, e senza alcun problema di prestazioni.&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;Schizzo di uno Storyboard: una table view con una cella prototipo vuota e una view SwiftUI disegnata a mano, indicata come rootView di un 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;Sopra c'è una bozza di ciò che vogliamo ottenere. Come si vede, la UITableViewCell deve conoscere la proprietà &lt;strong&gt;rootView&lt;/strong&gt; del corrispondente UIHostingController e, poiché ogni istanza di UITableViewCell deve essere riutilizzabile, dobbiamo mantenere questa proprietà unica.&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;Codice di CustomTableViewCell: crea un UIHostingController, ne vincola la view alla contentView in awakeFromNib e invia una notifica 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;Rendiamo la nostra CustomTableViewCell consapevole di questo creando una costante private che istanzia un &lt;strong&gt;UIHostingController&lt;/strong&gt; e configurando l'oggetto nella primissima fase di &lt;strong&gt;awakeFromNib&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Il metodo &lt;em&gt;configure(title:sfIcon:)&lt;/em&gt; è solo un segnaposto che sfrutta l'approccio &lt;strong&gt;Combine&lt;/strong&gt; / &lt;strong&gt;publisher&lt;/strong&gt; per comunicare con la corrispondente view &lt;strong&gt;SwiftUI&lt;/strong&gt;. Qui inviamo una semplice Notification quando dobbiamo configurare la SwiftUIView.&lt;/p&gt;
&lt;p&gt;Da notare che dobbiamo specificare la proprietà &lt;strong&gt;object&lt;/strong&gt;, perché vogliamo gestire &lt;em&gt;solo&lt;/em&gt; una specifica istanza dell'oggetto.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sì, lo ammetto, sembra davvero un hack...&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;Codice di GuestView, una HStack SwiftUI con un'immagine e un titolo che si aggiorna con un publisher di NotificationCenter e adotta 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;La controparte SwiftUI è molto semplice. Creiamo solo un contenitore HStack che ospita sia l'immagine di anteprima sia il titolo. Regoliamo anche il frame in modo da occupare tutto lo spazio disponibile senza ulteriori vincoli (la UIView che ci contiene sarà responsabile delle dimensioni del contenitore, N.d.R.). &lt;strong&gt;onReceive&lt;/strong&gt; aggiorneremo i relativi stati, facendo in modo che la view si aggiorni da sola dove serve.&lt;/p&gt;
&lt;p&gt;Noterete che ho fatto adottare Equatable alla struct stessa, aggiungendo sia un &lt;em&gt;id&lt;/em&gt; sia il relativo metodo in override. Serve per distinguere se dobbiamo scartare o prendere in considerazione la notifica pubblicata ricevuta da &lt;strong&gt;NotificationCenter&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ed è tutto. Anche se questa soluzione è un'architettura di cella molto hackish e sovradimensionata, sono davvero colpito dai risultati: lo scrolling è fluido e senza il minimo glitch.&lt;/p&gt;
&lt;p&gt;Sono abbastanza sicuro che esistano altri modi per ottenere lo stesso risultato con meno boilerplate e/o in modo molto più elegante (soprattutto per la comunicazione da UIKit a SwiftUI).&lt;/p&gt;
&lt;p&gt;Non vedo l'ora di leggere i vostri commenti e di vedere i vostri commit. Il codice completo è &lt;a href=&quot;https://github.com/valvoline/UIHostingTableViewTest&quot;&gt;disponibile qui&lt;/a&gt; su GITHUB.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Apple Silicon: ritorno al futuro</title>
    <link href="https://www.sofapps.it/it/blog/apple-silicon-back-to-the-future/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Il post paragona l'introduzione dell'M1 a quella dell'iPhone nel 2007, quando Blackberry fu improvvisamente scalzata dal podio. Apple controlla sia hardware sia software, mentre Dell, HP e Lenovo dipendono da Intel, e il suo vantaggio tecnologico è stimato in circa sei anni. Secondo l'autore né un'alleanza tra produttori né l'attesa di un cambio di rotta di Intel possono colmare il divario in fretta, per una ragione semplice: il tempo.</summary>
    <content type="html">&lt;p&gt;Il 2020 verrà ricordato come una pietra miliare per l'informatica, più o meno come il 2007 lo fu per la telefonia mobile.&lt;/p&gt;
&lt;p&gt;L'Apple di Tim Cook ha ancora una volta segnato un passo storico nel mondo dei computer. Non credo di esagerare paragonando l'introduzione dell'M1 alla storica presentazione dell'iPhone, che sicuramente tutti ricordiamo.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Certo, i tempi e gli attori sono molto diversi, ma il risultato finale (e l'esecuzione) lascia a bocca aperta allo stesso modo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Intel dovrà riorganizzare molte delle sue tabelle di marcia (preistoriche) per provare a ridurre il distacco. Il paragone con il 2007 mi viene naturale: allora Blackberry fu detronizzata dal podio all'improvviso e in modo quasi inaspettato, ma solo per chi non voleva guardare oltre il proprio naso. L'Intel di oggi ha una pipeline produttiva ormai capace solo di creare scaldapiedi. Non voglio sembrare di parte, ma a questo punto la realtà delle cose è più o meno questa.&lt;/p&gt;
&lt;p&gt;Il vero problema è che nel mondo dei computer le cose sono molto più complesse di quanto accadde per i telefoni nel 2007. I computer sono animali diversi, con flussi di lavoro e una cultura consolidati, composti da una miriade di piccoli componenti di terze parti: Intel non produce direttamente i computer finiti, ma solo una piccola parte di quei prodotti. E non è un caso.&lt;/p&gt;
&lt;p&gt;Apple, invece, fin dall'inizio ha scommesso tutto su un'integrazione totale e senza interruzioni tra hardware e software. Fermatevi un attimo a pensare:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;E se, quando tutto ebbe inizio, Wozniak avesse avuto le disponibilità finanziarie (come l'Apple multimilionaria di oggi) per costruirsi un processore tutto suo?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All'epoca le cose erano completamente diverse e Motorola era il partner più vicino nella battaglia contro un nemico comune. Per fortuna di Apple i tempi sono cambiati, e l'Apple di oggi non sembra interessata a &amp;quot;condividere&amp;quot; con il mondo il proprio vantaggio tecnologico (stimato in almeno 6 anni). Vale la pena ricordare che sei anni, nel campo dei computer, sono quasi un'era.&lt;/p&gt;
&lt;p&gt;Dell, HP, Lenovo e tutti gli altri hanno poco da fare, se non cercare di colmare il divario cominciando a correre. A mio parere le alternative sono solo due:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Creare un'alleanza (come fu per l'USB) e provare a costruire un processore il più simile possibile all'M1 di Apple.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Restare sulla barca di Intel, sperando che cambi radicalmente la propria impostazione e che qualcosa si muova il prima possibile.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Entrambe le soluzioni sono destinate a fallire per la stessa semplice ragione: il tempo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Qualunque scelta facciano i concorrenti, ci vorrà tempo. E se è vero, come dicono le voci, che Apple lavora all'M1 da oltre otto anni, questo dà un'idea chiara di quanto ci voglia per raggiungere chi è in testa.&lt;/p&gt;
&lt;p&gt;Nel frattempo Apple tornerà a occupare il podio dei &amp;quot;computer più venduti&amp;quot;, come nella prima metà degli anni 2000, e, c'è da sperarlo per lei, il circolo virtuoso di lock-in che lega l'ecosistema Apple sarà garantito almeno per il prossimo decennio.&lt;/p&gt;
&lt;p&gt;Steve Jobs non avrebbe potuto essere più orgoglioso del suo successore.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Programmare in SwiftUI: ObjectBinding e BindableObject</title>
    <link href="https://www.sofapps.it/it/blog/swiftui-programming-objectbinding/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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 è adatto ai value type posseduti da una sola View. Per una class condivisa tra più view SwiftUI offre @ObjectBinding insieme al protocol BindableObject, che pubblica i cambiamenti tramite un PassthroughSubject di Combine. Un'unica istanza fa da source of truth e ogni View la usa per riferimento.</summary>
    <content type="html">&lt;p&gt;In un &lt;a href=&quot;https://www.sofapps.it/it/blog/swiftui-programming-states/&quot;&gt;articolo precedente&lt;/a&gt; abbiamo visto che in &lt;strong&gt;SwiftUI&lt;/strong&gt; è possibile associare uno o più stati a una View tramite il modifier &lt;strong&gt;@State&lt;/strong&gt;; quest'ultimo deve essere usato con &lt;em&gt;&lt;strong&gt;value type&lt;/strong&gt;&lt;/em&gt; allocati all'interno della View che li dichiara. In questo modo la nostra applicazione è in grado di capire autonomamente quando aggiornare l'interfaccia utente in seguito ai cambiamenti della variabile marcata con @State che, ricordiamo, viene identificata come &lt;strong&gt;source of truth&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ma cosa succede se la nostra &lt;strong&gt;source of truth&lt;/strong&gt; è un &lt;em&gt;&lt;strong&gt;oggetto complesso&lt;/strong&gt;&lt;/em&gt;, progettato per esempio come una class? In questo caso @State fallisce il suo scopo, perché è pensato per lavorare esclusivamente con le property locali della nostra View.&lt;/p&gt;
&lt;p&gt;SwiftUI mette a disposizione un concetto più adatto a questo caso: &lt;strong&gt;@ObjectBinding&lt;/strong&gt;. Si può usare in tutti i casi in cui la property viene passata per riferimento, come accade con le 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;Copia&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;il-protocol-bindableobject&quot;&gt;Il protocol BindableObject&lt;/h2&gt;
&lt;p&gt;Le property con un modifier &lt;strong&gt;@ObjectBinding&lt;/strong&gt; si riferiscono quindi a oggetti di tipo class. Perché una class sia compatibile con il modifier @ObjectBinding, deve adottare il protocol &lt;strong&gt;BindableObject&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Nella sua variante più semplice il protocol &lt;strong&gt;BindableObject&lt;/strong&gt; è molto lineare e richiede soltanto che la nostra class implementi una property chiamata didChange, che notificherà gli oggetti View iscritti in modo che possano reagire correttamente ai cambiamenti dell'interfaccia visiva.&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;Copia&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;il-framework-combine-e-passthroughsubject&quot;&gt;Il framework Combine e PassthroughSubject&lt;/h2&gt;
&lt;p&gt;Perché funzioni, il codice precedente richiede di includere il supporto per il framework Combine all'inizio del nostro file swift.&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;Copia&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;Il &lt;strong&gt;framework Combine&lt;/strong&gt; è uno strumento molto potente e piuttosto complesso, che vedremo in un prossimo articolo. Per ora ci basta sapere che, tra le tante altre cose, fornisce una class chiamata &lt;strong&gt;PassthroughSubject&lt;/strong&gt; (la nostra property didChange è un'istanza di questa class). Ha il compito di notificare (Publishing) le parti interessate (Subscribers) che si è verificato un evento specifico.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PassthroughSubject&lt;/strong&gt;, come suggerisce il nome, si comporta in modo molto simile alle notifiche tradizionali messe a disposizione dal framework Foundation di Swift con NSNotificationCenter: l'oggetto specificato come parametro (nel nostro caso Void, dato che non vogliamo passare alcun parametro) viene passato così com'è, senza modifiche, al destinatario insieme a un &lt;em&gt;&lt;strong&gt;evento di notifica&lt;/strong&gt;&lt;/em&gt; che fa scattare una nuova ricostruzione della view.&lt;/p&gt;
&lt;p&gt;Se si vuole specificare un errore insieme alla notifica, lo si può passare come secondo parametro. Nel nostro esempio questa eventualità non ci interessa, ed è per questo che passiamo Never come secondo parametro nell'invocazione di PassthroughSubject.&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;Copia&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;Una volta creata un'istanza di tipo &lt;strong&gt;PassthroughSubject&lt;/strong&gt;, la possiamo usare per pubblicare il nostro evento ogni volta che vogliamo &lt;em&gt;notificare&lt;/em&gt; alle View iscritte i cambiamenti della nostra &lt;strong&gt;source of truth&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Per soddisfare quest'ultimo requisito usiamo il costrutto didSet messo a disposizione da Swift, che viene invocato ogni volta che cambia il valore di una property:&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;Copia&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;In questo modo, quando modifichiamo &lt;em&gt;someTextProperty&lt;/em&gt;, viene invocato il &lt;strong&gt;costrutto didSet&lt;/strong&gt;. Al suo interno chiamiamo il metodo send() dell'istanza di PassthroughSubject. Notate come specifichiamo un parametro di tipo Void passando al metodo una coppia di parentesi ().&lt;/p&gt;
&lt;p&gt;Così tutti gli oggetti iscritti ai cambiamenti (quelli che hanno dichiarato la loro property come &lt;strong&gt;@ObjectBinding&lt;/strong&gt;) sapranno che è arrivato il momento di aggiornare il loro 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;Semplice schema che illustra i riferimenti con 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: Semplice schema che illustra i riferimenti con ObjectBinding.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Come potete vedere dallo schema qui sopra, il nostro modello è caratterizzato da una &lt;strong&gt;singola istanza&lt;/strong&gt; in memoria, tramite una class conforme al &lt;strong&gt;protocol BindableObject&lt;/strong&gt;. I nostri oggetti View contengono un &lt;em&gt;riferimento&lt;/em&gt; all'oggetto originale.&lt;/p&gt;
&lt;p&gt;In questo modo si evita un problema tipico, la &lt;em&gt;duplicazione&lt;/em&gt; della source of truth: le modifiche al modello saranno uniche e porteranno all'aggiornamento immediato di tutte le view che fanno riferimento alla nostra 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;Semplice schema che illustra source of truth e 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: Semplice schema che illustra source of truth e ObjectBinding.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;un-esempio&quot;&gt;Un esempio&lt;/h2&gt;
&lt;p&gt;Proviamo a mettere in pratica i concetti precedenti con un esempio. Nell'articolo precedente avevamo configurato la nostra CustomTableViewCell per usare una variabile passata per valore, contenente una struct chiamata 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;Copia&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;Questo approccio non permetteva alla CustomTableViewCell di essere indipendente rispetto agli aggiornamenti del proprio contenuto: la variabile, infatti, veniva copiata durante la fase di init della CustomTableViewCell.&lt;/p&gt;
&lt;p&gt;Ogni modifica al suo contenuto era gestita tramite una variabile @State, posseduta da ContentView, che rigenerava la cella con il nuovo contenuto a ogni cambiamento.&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;Riferimento a State e a Object binding a confronto.&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: Riferimento a State e a Object binding a confronto.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Con il concetto di &lt;strong&gt;@ObjectBinding&lt;/strong&gt; possiamo rendere unico il &lt;em&gt;modello Person&lt;/em&gt;, passando alla CustomTableViewCell solo un riferimento, come mostrato nel grafico qui sopra a destra.&lt;/p&gt;
&lt;p&gt;La prima cosa da fare è modificare il nostro modello Person in modo che usi una class che &lt;em&gt;adotta&lt;/em&gt; il protocol &lt;strong&gt;BindableObject&lt;/strong&gt; al posto di una &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;Copia&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;Il nostro nuovo modello &lt;em&gt;adotta&lt;/em&gt; il protocol &lt;strong&gt;BindableObject&lt;/strong&gt; implementando la property &lt;strong&gt;didChange&lt;/strong&gt; tramite un'&lt;em&gt;istanza&lt;/em&gt; di &lt;strong&gt;PassthroughSubject&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ogni property interessata da possibili cambiamenti dell'interfaccia visiva (photoName, title e subtitle) è stata modificata in modo da reagire tramite il costrutto didSet. In questo modo, ogni volta che aggiorniamo una delle variabili, viene attivata la funzione update(), che a sua volta invia una notifica a tutti gli iscritti tramite l'istanza di PassthroughSubject.&lt;/p&gt;
&lt;p&gt;Infine modifichiamo la CustomTableViewCell per sfruttare il nuovo modello per riferimento. Per farlo basta anteporre il modifier @ObjectBinding di cui abbiamo parlato.&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;Copia&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;In questo modo la CustomTableViewCell non ha una copia del modello Person, ma lavora con un riferimento all'area di memoria in cui è conservato il modello originale. Vediamo dove e come creare il modello da passare per riferimento.&lt;/p&gt;
&lt;p&gt;Di questo requisito si occuperà ContentView, creando il modello vero e proprio in memoria e passandolo per riferimento alla 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;Copia&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-e-tableview&quot;&gt;List e TableView&lt;/h2&gt;
&lt;p&gt;Questa nuova versione di ContentView usa un nuovo oggetto chiamato List, che raggruppa gli elementi più o meno come il corrispettivo VStack. La differenza sta nella visualizzazione: il risultato sarà molto simile a una UITableView del framework UIKit.&lt;/p&gt;
&lt;p&gt;Quella che vediamo qui sopra è la forma di dichiarazione più semplice di List. Nel prossimo articolo vedremo come rendere dinamico il suo contenuto, in base al modello dichiarato.&lt;/p&gt;
&lt;p&gt;--A presto!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Programmare in SwiftUI: introduzione agli stati</title>
    <link href="https://www.sofapps.it/it/blog/swiftui-programming-states/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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 una view è una struct immutabile e @State permette al framework di allocare una variabile fuori da essa e ridisegnare il body ogni volta che il valore cambia. Si evitano così lo stato sparso e i problemi di threading di un view controller UIKit. Il post estrae anche una subview, le passa parametri e un modello, e mostra che @State non reagisce ai cambiamenti interni a una class.</summary>
    <content type="html">&lt;p&gt;Abbiamo visto in &lt;a href=&quot;https://www.sofapps.it/it/blog/swiftui-programming-classes-structs/&quot;&gt;un articolo precedente&lt;/a&gt; che in SwiftUI una View è una struct che &lt;em&gt;adotta&lt;/em&gt; il &lt;em&gt;protocol View&lt;/em&gt;. Quindi non eredita alcuna stored property, semplicemente perché non ha nessun padre; viene allocata sullo stack e gestita per valore e non per riferimento (come accade invece con le class in UIKit).&lt;/p&gt;
&lt;h2 id=&quot;come-funzionano-le-view-in-swiftui&quot;&gt;Come funzionano le view in SwiftUI&lt;/h2&gt;
&lt;p&gt;Dietro le quinte, &lt;strong&gt;SwiftUI&lt;/strong&gt; gestisce le View con l'aiuto di una struttura dati molto efficiente per il rendering a schermo dei contenuti. Per questo motivo è consigliabile usare e creare componenti &lt;strong&gt;specializzati&lt;/strong&gt; e &lt;strong&gt;riutilizzabili&lt;/strong&gt;. Durante lo sviluppo, Cupertino ci rassicura, non dobbiamo esitare a estrarre le view che svolgono un compito specifico e a creare per loro un oggetto View dedicato.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;Insieme al body, una View in SwiftUI definisce le sue dipendenze.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Supponiamo di voler creare in SwiftUI una View specializzata nel creare e gestire un pulsante. Il nostro oggetto dovrà occuparsi di un solo compito: alla pressione, la label dovrà cambiare riflettendo il nuovo stato.&lt;/p&gt;
&lt;p&gt;Ed è proprio qui che la programmazione dichiarativa dà il meglio: &lt;em&gt;&lt;strong&gt;la conseguenza di un'azione come modo per aggiornare l'interfaccia&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;l-attributo-state-in-swiftui&quot;&gt;L'attributo @State in SwiftUI&lt;/h2&gt;
&lt;p&gt;Il nostro pulsante avrà quindi una dipendenza tra il suo stato e la sua rappresentazione a schermo. In SwiftUI questa dipendenza è gestita automaticamente dal nuovo modifier @State. Proviamo con un esempio per capire meglio il concetto.&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;Copia&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; lega la variabile toggleStatus all'interfaccia: ogni volta che il suo valore cambia, SwiftUI sa che è necessario generare un nuovo body (e quindi aggiornare la label associata).&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;Semplice schema che illustra il flusso dei dati del codice precedente.&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: Semplice schema che illustra il flusso dei dati del codice precedente.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;provate-a-rimuovere-state-dal-codice-precedente-cosa-succede-e-perche&quot;&gt;Provate a rimuovere @State dal codice precedente. Cosa succede e perché?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Rimuovendo l'attributo @State, il compilatore si lamenterà perché stiamo cercando di modificare un valore immutabile: non dimentichiamo che abbiamo a che fare con una struct.
Ogni oggetto che viene renderizzato a schermo, infatti, è immutabile per ragioni di performance. In questo modo SwiftUI sa cosa deve essere aggiornato e cosa può essere lasciato fuori.
Aggiungendo un modifier @State, stiamo dicendo esplicitamente a SwiftUI:&lt;/p&gt;
&lt;p&gt;&amp;quot;Attenzione! Qui c'è un oggetto che potrebbe cambiare il suo stato, quindi dovrai aggiornarne il contenuto.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Di conseguenza, SwiftUI definisce implicitamente una dipendenza tra questa variabile e la presentazione a schermo della View ogni volta che incontra un attributo @State. In questo modo, ogni volta che la variabile cambia valore, SwiftUI sa che la View deve essere ridisegnata con il nuovo valore.&lt;/p&gt;
&lt;p&gt;Per fissare questo concetto e vedere quanto sia diverso dalla programmazione tradizionale, facciamo un confronto con 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;Copia&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;Naturalmente in &lt;strong&gt;UIKit&lt;/strong&gt; il codice qui sopra non basta per ottenere una schermata funzionante. Dovremo creare uno &lt;strong&gt;Storyboard&lt;/strong&gt; con un UIViewController e un UIButton. Dovremo inoltre allineare il pulsante al centro con i &lt;strong&gt;Constraints&lt;/strong&gt; e creare i riferimenti &lt;strong&gt;@IBOutlet&lt;/strong&gt; e &lt;strong&gt;@IBAction&lt;/strong&gt; corretti per far funzionare l'intero flusso.&lt;/p&gt;
&lt;p&gt;Lasciando da parte la quantità di codice e di operazioni, ovviamente maggiore rispetto a SwiftUI, concentriamoci sul nostro &lt;strong&gt;stato&lt;/strong&gt;. Anche in questo caso, infatti, il nostro pulsante deve conoscere lo stato corrente per poter cambiare la sua rappresentazione (la label). Notate come, nella programmazione imperativa tradizionale, ci siano due problemi concettuali importanti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;toggleStatus&lt;/strong&gt; è gestito (allocato, inizializzato e modificato) dal Controller.&lt;/li&gt;
&lt;li&gt;Non esiste un modo chiaro, a livello di codice, per separare le variabili che riguardano lo stato dell'interfaccia da quelle tradizionali: sono tutte uguali!&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;Uno schema che illustra le relazioni e il flusso del nostro oggetto Button 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: Uno schema che illustra le relazioni e il flusso del nostro oggetto Button in UIKit.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;È anche evidente come la complessità di questo approccio cresca in modo esponenziale all'aumentare del numero di oggetti e di stati.&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;Schema che illustra l'aumento della complessità al crescere degli stati gestiti dall'interfaccia.&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: Schema che illustra l'aumento della complessità al crescere degli stati gestiti dall'interfaccia.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;C'è ancora una cosa da sottolineare: iOS è un sistema operativo &lt;em&gt;&lt;strong&gt;multithreaded&lt;/strong&gt;&lt;/em&gt;. Questo significa che le richieste di aggiornamento dello stato e dell'interfaccia possono arrivare da più punti del codice e che i thread lavorano in modo indipendente l'uno dall'altro. Senza un modo chiaro per gestire situazioni di questo tipo si arriva a incoerenze nella UI e quindi a bug difficili da scoprire e da correggere.&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 un'applicazione multithreaded il confine tra chi aggiorna l'interfaccia e chi aggiorna lo stato non è chiaro.&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 un'applicazione multithreaded il confine tra chi aggiorna l'interfaccia e chi aggiorna lo stato non è chiaro.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;la-ricerca-della-verita&quot;&gt;La ricerca della verità&lt;/h2&gt;
&lt;p&gt;Ma come viene gestita in SwiftUI questa dipendenza tra variabili e interfaccia? E cosa rende il sistema resiliente e scalabile, a differenza di un approccio imperativo tradizionale?&lt;/p&gt;
&lt;p&gt;Quando SwiftUI elabora una View con una variabile di tipo @State, alloca in memoria uno spazio per questa variabile per conto della 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;Allocazione di una variabile @State 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: Allocazione di una variabile @State in SwiftUI.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Aggiungendo l'attributo &lt;strong&gt;@State&lt;/strong&gt; possiamo modificare un oggetto che sarebbe &lt;em&gt;&lt;strong&gt;altrimenti immutabile&lt;/strong&gt;&lt;/em&gt;, come una struct: dietro le quinte, infatti, la variabile viene allocata dal framework SwiftUI in un'area di lettura/scrittura dell'applicazione.&lt;/p&gt;
&lt;p&gt;In SwiftUI ogni possibile stato di una View (l'offset di una scrollview, lo stato di un pulsante, il contenuto di uno stack e così via) è gestito da questo concetto, noto come &lt;strong&gt;Source of Truth&lt;/strong&gt;. Seguendo questo concetto è possibile classificare ogni variabile come &lt;em&gt;&lt;strong&gt;source of truth&lt;/strong&gt;&lt;/em&gt; oppure come &lt;em&gt;&lt;strong&gt;valore derivato&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;Schema che mostra la classificazione delle variabili 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: Schema che mostra la classificazione delle variabili in SwiftUI.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Nel nostro esempio, &lt;strong&gt;toggleStatus&lt;/strong&gt; è una &lt;strong&gt;source of truth&lt;/strong&gt;. Inoltre, dallo schema qui sopra possiamo dedurre che anche tutte le &lt;strong&gt;costanti&lt;/strong&gt; sono una source of truth, mentre una semplice property è un valore derivato.&lt;/p&gt;
&lt;p&gt;Vedremo nei prossimi capitoli che esiste un altro meccanismo per passare valori derivati in lettura/scrittura, chiamato &lt;strong&gt;@Binding&lt;/strong&gt;. Con un esempio pratico vedremo anche in cosa un valore derivato differisce dalla corrispondente source of truth. Analizzeremo le differenze con &lt;strong&gt;@State&lt;/strong&gt; e come e quando usare l'uno rispetto all'altro.&lt;/p&gt;
&lt;h2 id=&quot;organizzare-il-codice-l-estrazione-delle-view&quot;&gt;Organizzare il codice: l'estrazione delle view&lt;/h2&gt;
&lt;p&gt;Ora che abbiamo chiaro come una View si aggiorna e ricostruisce il suo contenuto, proviamo a mettere insieme quello che abbiamo imparato con l'esempio dell'ultimo articolo. L'ultima volta avevamo lasciato la nostra ContentView così:&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;Copia&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;Chiaramente questo approccio non è mantenibile. Il codice tende ad annidarsi e a crescere verso destra, nella cosiddetta &lt;a href=&quot;https://itnext.io/pyramid-of-doom-the-signs-and-symptoms-of-a-common-anti-pattern-c716838e1819&quot;&gt; &amp;quot;pyramid of doom&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All'inizio dell'articolo abbiamo accennato a un meccanismo per estrarre le subview, così da rendere il codice scalabile e mantenibile. Vediamo cosa ci offrono il nuovo Xcode 11 e SwiftUI per risolvere questo problema.&lt;/p&gt;
&lt;p&gt;Assicuratevi di usare Xcode 11 e portate il mouse sul tag HStack. Tenendo premuto il tasto CMD (⌘), cliccate sul tag, come segue:&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 crea automaticamente una nuova struct e ci dà la possibilità di cambiarne il nome.&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 crea automaticamente una nuova struct e ci dà la possibilità di cambiarne il nome.&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 crea automaticamente una nuova struct e ci dà la possibilità di cambiarne il nome.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Xcode crea automaticamente una nuova struct, estrae il contenuto selezionato e lo usa per popolare il body dell'oggetto appena generato. Alla fine dell'operazione ci offre anche la possibilità di cambiare il nome: rinominate la View estratta in &lt;strong&gt;CustomTableViewCell&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La nuova versione di &lt;strong&gt;ContentView&lt;/strong&gt; è ora molto più leggibile e leggera, e contiene solo un riferimento a un nuovo oggetto. Come ulteriore comodità, potremmo anche spostare il contenuto di &lt;strong&gt;CustomTableViewCell&lt;/strong&gt; in un nuovo file, per isolare meglio il concetto di componente.&lt;/p&gt;
&lt;h2 id=&quot;passare-parametri&quot;&gt;Passare parametri&lt;/h2&gt;
&lt;p&gt;Non sarebbe interessante passare i parametri giusti alla nostra nuova CustomTableViewCell, per generare una cella con contenuti dinamici come titolo, sottotitolo e immagine? Proviamo a modificare la nostra nuova struct per ottenere questo risultato:&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;Copia&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;Ora, dentro la &lt;strong&gt;ContentView&lt;/strong&gt;, la nostra &lt;strong&gt;CustomTableCell&lt;/strong&gt; può essere creata con parametri che ne definiscono in modo univoco il contenuto.&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;Copia&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;E se volessimo spingerci oltre e creare, per esempio, un pulsante che cambia il contenuto del campo subtitle?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;il-modello-l-oggetto-e-swiftui&quot;&gt;Il modello, l'oggetto e SwiftUI&lt;/h2&gt;
&lt;p&gt;Il modello collegato a un oggetto View ha un ruolo fondamentale nel paradigma dichiarativo di SwiftUI. Ogni oggetto ha tipicamente un modello associato che, insieme allo stato, identifica completamente l'interfaccia utente mostrata.&lt;/p&gt;
&lt;p&gt;Per esempio, potremmo associare alla nostra &lt;strong&gt;CustomTableViewCell&lt;/strong&gt; un modello di questo tipo:&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;Copia&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;Di conseguenza dovremo modificare la nostra View per sfruttare il nuovo modello appena creato:&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;Copia&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;Infine, la &lt;strong&gt;ContentView&lt;/strong&gt; deve riflettere questa modifica per mostrare correttamente a schermo la nostra &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;Copia&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;Questa volta la variabile model ha l'attributo &lt;strong&gt;@State&lt;/strong&gt;: il proprietario del modello è l'oggetto &lt;strong&gt;ContentView&lt;/strong&gt;, che lo passa per copia (&lt;em&gt;&lt;strong&gt;ricordiamo che stiamo lavorando con struct e non con class&lt;/strong&gt;&lt;/em&gt;) alla &lt;strong&gt;CustomTableViewCell&lt;/strong&gt;, la quale a sua volta lo usa per mostrare i campi corrispondenti dei suoi oggetti: Image e Text.&lt;/p&gt;
&lt;p&gt;Il pulsante ha un'azione che aggiorna il modello cambiandone il subtitle. Poiché ContentView ha aggiunto l'attributo &lt;strong&gt;@State&lt;/strong&gt; al suo modello, ogni modifica di quest'ultimo fa scattare l'aggiornamento del suo body che, a sua volta, &lt;em&gt;rigenera&lt;/em&gt; una nuova CustomTableViewCell con il contenuto aggiornato.&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;Schema di flusso che illustra l'aggiornamento dello stato dell'oggetto.&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: Schema di flusso che illustra l'aggiornamento dello stato dell'oggetto.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Avrete notato che ho aggiunto l'attributo &lt;strong&gt;private&lt;/strong&gt; prima di dichiarare la variabile di stato del modello. Questo perché, come abbiamo spiegato sopra, le variabili marcate con &lt;strong&gt;@State&lt;/strong&gt; appartengono esclusivamente alla View che le dichiara. È quindi una buona idea rafforzare questo concetto marcandole come private.&lt;/p&gt;
&lt;p&gt;Vedremo nel prossimo articolo che &lt;strong&gt;SwiftUI&lt;/strong&gt; espone altri modi per gestire i parametri e l'injection quando ci troviamo in situazioni come quella illustrata sopra. In questo caso, infatti, pur essendo corretto dal punto di vista sintattico e funzionale, il nostro flusso soffre di un piccolo problema: la nostra CustomTableViewCell usa una propria copia del modello, che a sua volta è esposto, allocato e gestito da ContentView con una variabile privata.&lt;/p&gt;
&lt;p&gt;SwiftUI offre astrazioni molto simili all'attributo @State per gestire queste circostanze e permettere al modello di propagarsi correttamente dove serve.&lt;/p&gt;
&lt;h3 id=&quot;cosa-succede-se-cambiamo-il-modello-da-struct-a-class&quot;&gt;Cosa succede se cambiamo il modello da struct a class?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Anche se il progetto continuerà a compilare e a girare senza problemi, purtroppo noteremo che in pratica il pulsante non cambierà più il contenuto del campo subtitle.&lt;/p&gt;
&lt;p&gt;@State funziona con i value type, mentre le class sono reference type: cambiando il valore di una class marcata con l'attributo @State, la sua modifica interna non fa scattare l'aggiornamento del body.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;-- 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Programmare in SwiftUI: costruire view più complesse</title>
    <link href="https://www.sofapps.it/it/blog/swiftui-programming-complex-views/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>I container come VStack costruiscono il loro contenuto con una closure ViewBuilder, che sostituisce addSubview e i constraint di Auto Layout con una composizione dichiarativa. Il post costruisce una riga con titolo, sottotitolo e immagine circolare usando stack, modifier e Spacer. Segnala anche che if let non è accettato dentro un ViewBuilder.</summary>
    <content type="html">&lt;p&gt;Abbiamo visto che SwiftUI richiede sempre di esporre un &lt;strong&gt;body&lt;/strong&gt; che restituisce una View. Nella costruzione di view complesse, però, è necessario comporre queste View con un &lt;strong&gt;layout specifico&lt;/strong&gt; e restituirle sotto forma di &lt;strong&gt;un unico oggetto&lt;/strong&gt;. Per farlo SwiftUI ci viene in aiuto attraverso il concetto di &lt;em&gt;Content View&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Gli oggetti di base con cui abbiamo a che fare, come Text che abbiamo visto nel capitolo precedente, &lt;em&gt;adottano&lt;/em&gt; il &lt;strong&gt;protocol View&lt;/strong&gt;. Ci sono altri oggetti, più complessi, che nella dichiarazione della loro API hanno un formato simile a questo:&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;Copia&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;Quella qui sopra è la dichiarazione del componente &lt;strong&gt;VStack&lt;/strong&gt;, che analizzeremo nel resto dell'articolo. Se guardiamo la definizione di Content, vedremo che:&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;Copia&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;In pratica, oggetti come &lt;strong&gt;VStack&lt;/strong&gt; usano un costruttore &lt;strong&gt;ViewBuilder&lt;/strong&gt; per comporre insieme più tipi di View.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;la-closure-viewbuilder&quot;&gt;La closure ViewBuilder&lt;/h2&gt;
&lt;p&gt;La closure ViewBuilder ci permette di inserire al suo interno istruzioni tipicamente dichiarative: invece di invocare un metodo &lt;strong&gt;addSubview&lt;/strong&gt;, come facevamo con &lt;strong&gt;UIKit&lt;/strong&gt;, inseriremo una lista con tutte le view contenute &lt;em&gt;&lt;strong&gt;direttamente&lt;/strong&gt;&lt;/em&gt; nella closure.&lt;/p&gt;
&lt;p&gt;Per capire meglio questo concetto, guardiamo più da vicino la definizione della struct 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;Copia&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;Il parametro content è definito come una closure &lt;strong&gt;() -&amp;gt; Content&lt;/strong&gt;. Il compilatore riconosce questo attributo come implicitamente marcato con &lt;strong&gt;@ViewBuilder&lt;/strong&gt; e sa come trasformarlo in una nuova closure che restituisce una view rappresentante tutto il contenuto dichiarato dentro &lt;strong&gt;VStack&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;Questo principio è presente in tutti gli oggetti che espongono una clausola where Content: View&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;Una Stack View è una View speciale di tipo Container View che ci permette di restituire una composizione di altri oggetti View, secondo un layout verticale, orizzontale o in profondità.&lt;/p&gt;
&lt;p&gt;Continuando i nostri confronti con il framework &lt;strong&gt;UIKit&lt;/strong&gt;, l'oggetto corrispondente che analizzeremo in questo paragrafo è &lt;strong&gt;UIStackView&lt;/strong&gt;. In SwiftUI, però, a parte l'idea di base, resta ben poco della classica UIStackView.&lt;/p&gt;
&lt;p&gt;Gli stack attualmente disponibili sono di tre tipi: &lt;strong&gt;HStack&lt;/strong&gt;, &lt;strong&gt;VStack&lt;/strong&gt; e &lt;strong&gt;ZStack&lt;/strong&gt;. Rispettivamente: Horizontal Stack, Vertical Stack e Depth Stack (Z indica la dimensione della profondità).&lt;/p&gt;
&lt;p&gt;Questi oggetti, insieme ai modifier che abbiamo visto nel capitolo precedente, ci permettono di &lt;em&gt;&lt;strong&gt;sostituire completamente&lt;/strong&gt;&lt;/em&gt; il concetto di Auto Layout e Constraints. Dal punto di vista tecnico questo aumenta molto la reattività e la velocità di rendering dell'applicazione, perché il sistema non deve pre-calcolare nessun constraint o layout specifico: tutto è dichiarato a priori, in puro stile dichiarativo.&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;Una semplice gerarchia che mostra un tipico uso di VStack.&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: Una semplice gerarchia che mostra un tipico uso di VStack.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Nel codice scriveremo qualcosa del genere:&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;Copia&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;Come potete vedere, a differenza di UIKit, i riferimenti a metodi come addSubview non ci sono più. In SwiftUI le view si creano interamente con un processo di composizione dichiarativa delle struct. Semplicemente, diciamo al compilatore che la nostra ContentView contiene un container VStack che a sua volta contiene: Image, Text, Text, Text e Slider.&lt;/p&gt;
&lt;p&gt;Per ora non ci preoccupiamo dei singoli metodi di creazione. Avremo modo di tornare tra poco sulle immagini e sui controlli avanzati come lo slider. Per ora l'importante è capire esattamente cosa sta succedendo e perché.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Una nota molto importante sul ViewBuilder riguarda la sintassi da usare al suo interno. Anche se siamo in presenza di Swift, dentro questa closure non è possibile usare alcuni operatori tipici a cui siamo abituati, come l'optional unwrapping:&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;Copia&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;Questo codice produrrà un errore di compilazione. La closure ViewBuilder non è in grado, per ora, di interpretare correttamente il concetto di optional unwrapping. Il codice seguente, invece, funziona correttamente:&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;Copia&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;costruire-una-tableviewcell-personalizzata&quot;&gt;Costruire una TableViewCell personalizzata&lt;/h2&gt;
&lt;p&gt;Dato che il modo più semplice per imparare un nuovo strumento è metterlo in pratica, in questa sezione proveremo a replicare il comportamento tipico di una UITableViewCell con titolo e sottotitolo. Il risultato che vorremmo ottenere è qualcosa del genere:&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;La TableViewCell che vorremmo ottenere.&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: La TableViewCell che vorremmo ottenere.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;La prima cosa da fare è creare un nuovo progetto con il supporto per 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;I passi da seguire&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;I passi da seguire&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: I passi da seguire&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Ora sostituiamo la struct &lt;strong&gt;ContentView&lt;/strong&gt; fornita di default con il codice seguente:&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;Copia&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;A questo punto, nel pannello &lt;strong&gt;Preview Canvas&lt;/strong&gt; dovreste vedere comparire come per magia il risultato delle vostre istruzioni:&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;Il pannello Preview di Xcode 11 mostra il risultato delle nostre dichiarazioni al framework SwiftUI.&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: Il pannello Preview di Xcode 11 mostra il risultato delle nostre dichiarazioni al framework SwiftUI.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Se non vedete nulla, assicuratevi prima di tutto di lavorare su macOS Catalina 10.15: il sistema di Live Preview funziona esclusivamente in questo ambiente. Se siete già su 10.15 ma non vedete ancora la live preview, verificate di aver attivato il pannello Canvas come segue:&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;Perché la Live Preview funzioni bisogna essere su Catalina 10.15 e aver attivato il pannello Canvas.&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: Perché la Live Preview funzioni bisogna essere su Catalina 10.15 e aver attivato il pannello Canvas.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Semplice? Certo! Ci mancano ancora alcuni elementi per completare il lavoro. La prima cosa è l'immagine. Scaricate l'immagine di riferimento che trovate in fondo all'articolo e, dopo aver selezionato la cartella Assets.xcassets del vostro progetto, trascinateci dentro l'immagine appena scaricata.&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;Importare un'immagine per il nostro esercizio nella cartella degli asset.&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: Importare un'immagine per il nostro esercizio nella cartella degli asset.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;l-oggetto-image&quot;&gt;L'oggetto Image&lt;/h2&gt;
&lt;p&gt;Ogni framework deve poter dialogare, in modo più o meno completo e complesso, con le immagini. &lt;strong&gt;SwiftUI&lt;/strong&gt; offre un supporto davvero notevole per questo tipo di oggetti, che non farà rimpiangere nemmeno il suo cugino &lt;strong&gt;UIImageView&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image&lt;/strong&gt; è un oggetto View (il risultato è un oggetto conforme al protocol View). Nella sua forma più semplice, gli forniamo il nome di un'immagine da mostrare:&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;Copia&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;Il risultato è una View con l'immagine passata come argomento. Se proviamo a inserire questa istruzione dentro la 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;Copia&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;il risultato non sarà esattamente quello sperato:&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;Il primo tentativo con Image non è esattamente quello sperato!&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: Il primo tentativo con Image non è esattamente quello sperato!&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Proviamo a risolvere il problema. La prima cosa da fare è allineare l'immagine in orizzontale con il resto del contenuto. Vi ricordate quando parlavamo di VStack?&lt;/p&gt;
&lt;p&gt;Il suo compito è allineare verticalmente la lista di elementi forniti nel suo blocco ViewBuilder. È chiaro, quindi, che bisogna modificare leggermente lo schema delle view su cui stiamo lavorando, aggiungendo un'ulteriore variante di Stack fornita da 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;Il nuovo schema ad albero di come vorremmo modificare la nostra 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: Il nuovo schema ad albero di come vorremmo modificare la nostra 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;Copia&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;Secondo tentativo&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: Secondo tentativo&lt;/figcaption&gt;&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Molto meglio!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Dobbiamo ancora sistemare la &lt;strong&gt;forma&lt;/strong&gt; e la &lt;strong&gt;dimensione&lt;/strong&gt; dell'immagine. La prima cosa da fare è dire alla nostra immagine che deve essere ridimensionabile e mantenere il suo 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;Copia&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;Poi vorrei darle una forma circolare e forzarne la dimensione a 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;Copia&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;e, infine, vorrei aggiungere un po' di padding a sinistra, diciamo 20 punti:&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;Copia&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;Tutto insieme:&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;Copia&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;l-oggetto-spacer&quot;&gt;L'oggetto Spacer&lt;/h2&gt;
&lt;p&gt;A questo punto la nostra &lt;strong&gt;CustomTableView&lt;/strong&gt; sembra completa, ma resta un piccolo problema: sembra allineata al centro invece che a sinistra.&lt;/p&gt;
&lt;p&gt;Il problema dipende dal fatto che gli stack, per impostazione predefinita (ricordo che quello su cui stiamo lavorando si espande in orizzontale, HStack), sono pensati per occupare tutto lo spazio disponibile sul loro asse principale, dividendolo in parti uguali tra i figli.&lt;/p&gt;
&lt;p&gt;Quindi, per allineare tutto l'oggetto a sinistra, bisogna aggiungere un'ulteriore view neutra chiamata Spacer. La View Spacer è una view flessibile che si espande automaticamente lungo tutto l'asse principale dello stack in cui viene inserita. Aggiungeremo questa View come ultimo elemento del nostro stack orizzontale:&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;Copia&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;Ecco come apparirà la nostra preview a lavoro completato:&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;La gerarchia ad albero finale della 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;La gerarchia ad albero finale della 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: La gerarchia ad albero finale della CustomTableViewCell.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Nota: l'attuale versione di Xcode 11 contiene un problema noto che non ridimensiona correttamente l'immagine quando si usa l'opzione .fit, producendo invece una sorta di effetto di stiramento del contenuto.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nel prossimo capitolo vedremo alcune regole di buona condotta per rendere il codice il più minimale e compatto possibile, adottando tecniche di estrazione delle subview. Vedremo anche un'introduzione al passaggio dei parametri e a come SwiftUI gestisce lo stato dei suoi elementi.&lt;/p&gt;
&lt;p&gt;-- 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Programmare in SwiftUI: class e struct in SwiftUI</title>
    <link href="https://www.sofapps.it/it/blog/swiftui-programming-classes-structs/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Dichiarare una View come semplice class non funziona, perché una class può avere sottoclassi e il protocol View non potrebbe garantire l'unicità di Self. Marcare la class come final elimina il problema. A quel punto, se serve davvero, si può usare una class in SwiftUI.</summary>
    <content type="html">&lt;p&gt;Sono piuttosto sicuro che a tutti sia venuta in mente, almeno una volta, questa domanda.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Se il concetto alla base di una View è il protocol, cosa succede se provo a usare una class?&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Proviamo ad analizzarla nel dettaglio.&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;Copia&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;Il codice qui sopra, pur essendo sintatticamente perfetto, produce un errore. Il compilatore si lamenta del fatto che la class è troppo mutevole durante l'esecuzione. Una class è infatti indeterminata per sua natura: cosa succederebbe se la stessa ContentView avesse una sottoclasse?&lt;/p&gt;
&lt;p&gt;Il protocol View non saprebbe come garantire l'unicità. * Self * continuerebbe a riferirsi a ContentView e la sottoclasse violerebbe questa regola.&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;Copia&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;oppure, più semplicemente:&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;Copia&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;A questo punto, se è davvero necessario, possiamo usare una class per lavorare in SwiftUI.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Programmare in SwiftUI: l'oggetto View</title>
    <link href="https://www.sofapps.it/it/blog/swiftui-programming-view-object/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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 una View è una struct che adotta il protocol View, il cui unico requisito è un body che restituisce un'altra View. Le interfacce complesse sono alberi di piccole view componibili. Il tipo di ritorno some View è un opaque type: a differenza di un protocol conserva il tipo concreto, quindi una funzione può restituire un solo tipo di oggetto.</summary>
    <content type="html">&lt;p&gt;Abbiamo visto che &lt;strong&gt;SwiftUI&lt;/strong&gt; è un framework dichiarativo. Il risultato visivo che vediamo sul nostro dispositivo nasce da una serie di istruzioni con cui diciamo al compilatore come vogliamo vedere la nostra interfaccia. Ma se la UIView era il cuore pulsante di UIKit, qual è l'equivalente in SwiftUI? La risposta è un nuovo oggetto, chiamato View.&lt;/p&gt;
&lt;h2 id=&quot;che-cos-e-una-view&quot;&gt;Che cos'è una View?&lt;/h2&gt;
&lt;p&gt;La prima vera grande differenza rispetto a una &lt;strong&gt;UIView&lt;/strong&gt; è che in SwiftUI una &lt;strong&gt;View&lt;/strong&gt; è una struct che adotta un protocol. L'esempio base fornito da Apple comincia così:&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;Copia&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;Quello qui sopra è un oggetto SwiftUI perfettamente funzionante, chiamato ContentView, che contiene (restituisce) nel suo body una label con &amp;quot;Hello World&amp;quot;.&lt;/p&gt;
&lt;p&gt;Noterete che ho parlato di &amp;quot;contenere&amp;quot; (return l'ho solo accennato tra parentesi). Uno dei cardini di SwiftUI è infatti la riusabilità del codice e il concetto di View riutilizzabili come se fossero mattoncini Lego ™.&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;Gerarchia ad albero dell'esempio precedente.&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: Gerarchia ad albero dell'esempio precedente.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;Una view, quindi, definisce un pezzo della nostra User Interface.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Tutto in un'app SwiftUI può essere ricondotto a una View, che definisce un pezzo della nostra interfaccia. Di conseguenza, le view complesse sono costruite a partire da elementi semplici che cooperano tra loro, formando una gerarchia ad albero. Dietro le quinte, il compilatore gestisce tutte le View e le traduce in una struttura dati molto efficiente che mostra a schermo il contenuto richiesto. Ma come funziona questa composizione?&lt;/p&gt;
&lt;h2 id=&quot;un-solo-requisito-body&quot;&gt;Un solo requisito: body&lt;/h2&gt;
&lt;p&gt;Abbiamo detto che una View è una struct che adotta il protocol View. L'unico requisito di questo protocol è fornire alla nostra View un body, responsabile del contenuto del nostro oggetto. Il body è una closure speciale che restituisce un contenuto anch'esso sotto forma di View. Per esempio, nel codice di Apple visto sopra:&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;Copia&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 questo caso il body della nostra View è un componente di base, chiamato Text, che a sua volta restituisce un oggetto conforme al tipo some View richiesto dal body. Questa sintassi fa parte di un concetto nuovo introdotto con Swift 5.1, chiamato Opaque Types. Per ora basta sapere che l'opaque type richiesto dal body ci permette di scambiare oggetti di cui non conosciamo in anticipo il tipo specifico, ma che è ben determinato a livello di compilazione (a differenza di un semplice protocol).&lt;/p&gt;
&lt;h2 id=&quot;opaque-types&quot;&gt;Opaque types&lt;/h2&gt;
&lt;p&gt;Restituire un opaque type sembra molto simile a usare un protocol, ma i due costrutti differiscono perché l'opaque type conserva il tipo. Un opaque type si riferisce a un tipo specifico, anche se chi chiama la funzione non è in grado di vedere quale sia. Un protocol, invece, può riferirsi a qualunque tipo che lo adotti: offre quindi più flessibilità sul tipo restituito, mentre gli opaque type ci danno garanzie precise sul tipo restituito.&lt;/p&gt;
&lt;p&gt;Facciamo un esempio per chiarire meglio il concetto:&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;Copia&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;Il protocol Humanoid è adottato da due struct: Man e Woman. La funzione child restituisce un Humanoid che può essere, con uguale probabilità, uno dei due casi. A questo punto creiamo due istanze di Humanoid:&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;Copia&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;e, siccome siamo curiosi di sapere se i nostri figli sono maschi o femmine, proviamo a confrontarli:&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;Copia&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;A questo punto il compilatore ci rimprovererà, giustamente, perché Humanoid non è confrontabile: non adotta il protocol Equatable. Niente male, penserete. Proviamo ad adottarlo:&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;Output del Playground.&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: Output del Playground.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Il problema è che Humanoid non può essere confrontato perché Swift non ha alcuna garanzia che gli elementi restituiti siano di un tipo confrontabile. Ricordo che qualunque struct può adottare il protocol, implementando i metodi richiesti.&lt;/p&gt;
&lt;p&gt;Per risolvere questo problema sono nati gli opaque type. Il codice precedente può essere trasformato così:&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;Copia&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;Un'osservazione importante sul codice qui sopra: come potete vedere, ho dovuto creare due funzioni diverse (boy per il maschio, girl per la femmina), perché uno dei requisiti principali quando si lavora con un opaque type è che &lt;strong&gt;i metodi devono restituire un solo tipo di oggetto&lt;/strong&gt;. Ritroverete questo concetto molto spesso in SwiftUI quando lavoreremo con le View.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Programmare in SwiftUI: introduzione</title>
    <link href="https://www.sofapps.it/it/blog/swiftui-programming-introduction/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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 è la risposta di Apple ai framework dichiarativi diffusi sul web e nello sviluppo mobile. Non esistono controller: l'interfaccia è derivata dallo stato e viene ricostruita quando lo stato cambia. Questo post apre una serie di appunti di studio sul framework.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;SwiftUI&lt;/strong&gt; segna sicuramente l'inizio di un nuovo capitolo nella storia dello sviluppo in casa Apple. Da anni assistiamo al proliferare di framework basati sul concetto di interfacce dichiarative: il web ne è un esempio lampante, ma non mancano esempi illustri nello sviluppo mobile. Siamo continuamente bombardati da messaggi di marketing che affermano come:&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;mantenere un'unica codebase per tutte le piattaforme è il modo migliore per aumentare la produttività aziendale e fornire soluzioni efficaci ai nostri clienti.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;React Native&lt;/strong&gt; (Facebook) e &lt;strong&gt;Flutter&lt;/strong&gt; (Google) sono un esempio eccellente di questa proposta. Non è scopo di questo articolo fare un'analisi comparativa di queste tecnologie: ho citato questi due esempi per mostrare come la tendenza del software negli ultimi anni si stia muovendo in direzioni diverse da quelle a cui siamo stati abituati finora.&lt;/p&gt;
&lt;p&gt;I nostri dispositivi sono sempre più potenti e questa potenza trova la sua naturale collocazione in interfacce e paradigmi di interazione sempre più sofisticati e complessi. L'anno scorso &lt;a href=&quot;https://www.sofapps.it/it/blog/iphone-x-peripheral-vision/&quot;&gt;scrissi un pezzo&lt;/a&gt; sull'uscita di iPhone X e sulla sensazione di fluidità che questo nuovo dispositivo, unito alle ultime scelte stilistiche di iOS 11 e 12, mi aveva suscitato.&lt;/p&gt;
&lt;p&gt;Animazioni fluide, continue e coerenti, gesture fuse nell'esperienza di navigazione. Sono solo alcuni esempi di quello che sto cercando di trasmettervi: l'asticella delle aspettative si è alzata ancora una volta e queste nuove caratteristiche non sono facilmente esprimibili con un framework tradizionale.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;La natura discreta dei linguaggi imperativi è in forte difficoltà, rispetto al senso di continuità e fluidità imposto dalle nuove interfacce.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Apple è sempre stata una società molto conservativa (&lt;strong&gt;Objective-C&lt;/strong&gt; continua a funzionare e a compilare senza problemi) riguardo ai propri ambienti di sviluppo e, in generale, a tutto il suo ecosistema. L'introduzione di &lt;strong&gt;Swift&lt;/strong&gt;, 5 anni fa, con i suoi nuovi paradigmi e la sua sferzata di modernità era già stata un grosso segnale di cambiamento da parte di Cupertino. Ma era chiaro che non bastava. Così, a sorpresa per tutti, ecco arrivare la risposta di Apple agli altri colossi del web: &lt;strong&gt;SwiftUI&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;SwiftUI è un framework dichiarativo orientato ai componenti. Dimentichiamoci, dunque, del pattern &lt;strong&gt;MVC&lt;/strong&gt;, dove i controller facevano da mediatori tra view e modelli. Tutto quello che abbiamo in SwiftUI è uno stato e una view derivata dallo stato. Non appena lo stato cambia, SwiftUI ricostruisce l'interfaccia tenendo conto delle modifiche.&lt;/p&gt;
&lt;p&gt;Quelli che seguono sono i nostri appunti di viaggio personali, presi durante lo studio di questo framework così nuovo e, per certi versi, misterioso. Abbiamo ritenuto utile condividerli con tutti voi, nella speranza che siano un punto di partenza per imparare qualcosa di davvero entusiasmante.&lt;/p&gt;
&lt;p&gt;--Buon viaggio!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>TextField e UIViewRepresentable</title>
    <link href="https://www.sofapps.it/it/blog/textfield-uiviewrepresentable/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Il TextField di SwiftUI in iOS 13 beta 2 non permetteva di spostare il focus tra campi e non chiamava mai onCommit. Il post incapsula in una struct UIViewRepresentable una UITextField che fa da delegate di se stessa, usando closure per i cambi e per la fine dell'editing e i tag delle view per passare il focus al campo successivo.</summary>
    <content type="html">&lt;p&gt;A prima vista, quando ho provato SwiftUI per la prima volta dopo la presentazione del WWDC19, una delle preoccupazioni più grandi riguardava sicuramente l'oggetto TextField: non c'era modo di chiudere la tastiera, né di spostare il focus da un TextField all'altro.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;probabilmente alcuni dettagli non erano ancora pronti durante la presentazione iniziale.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;iOS13 beta2&lt;/strong&gt;, insieme a molti altri miglioramenti, sembra risolvere almeno in parte i problemi legati al &lt;strong&gt;TextField&lt;/strong&gt;: quando si preme il tasto Invio, la tastiera ora viene chiusa correttamente. Non ci sono indizi, però, su un meccanismo per &lt;strong&gt;cambiare il focus&lt;/strong&gt; tra &lt;strong&gt;più&lt;/strong&gt; TextField all'interno dello stesso container View. Purtroppo dobbiamo anche segnalare un &lt;strong&gt;bug importante&lt;/strong&gt; della beta2 che riguarda il meccanismo di chiamata della closure &lt;strong&gt;onCommitHandler&lt;/strong&gt; quando la tastiera viene chiusa: quest'ultima non viene mai chiamata.&lt;/p&gt;
&lt;p&gt;In questo articolo proveremo ad aggirare tutti questi problemi creando un &lt;strong&gt;TextField&lt;/strong&gt; personalizzato che prende il meglio di quello che c'è oggi in &lt;strong&gt;SwiftUI&lt;/strong&gt; e in &lt;strong&gt;UIKit&lt;/strong&gt;. I lettori più attenti avranno probabilmente già capito dove voglio arrivare:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Costruiremo un componente personalizzato in UIKit che usa la vecchia e perfettamente funzionante UITextField e lo esporremo in SwiftUI attraverso il protocol UIViewRepresentable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;uitextfield-e-i-delegate&quot;&gt;UITextField e i delegate&lt;/h2&gt;
&lt;p&gt;UIKit mette a disposizione un oggetto chiamato &lt;strong&gt;UITextField&lt;/strong&gt; che sfrutta la &lt;strong&gt;tecnica del delegate&lt;/strong&gt; per offrire un'esperienza di tastiera fluida ed efficace.&lt;/p&gt;
&lt;p&gt;Quello che faremo è creare una class che eredita da &lt;strong&gt;UITextField&lt;/strong&gt; e, allo stesso tempo, adotta il protocol &lt;strong&gt;UITextFieldDelegate&lt;/strong&gt;. In questo modo avremo un unico oggetto da esporre per l'integrazione con &lt;strong&gt;SwiftUI&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La prima cosa da fare è dichiarare la nostra class, che chiameremo &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;Copia&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;Il codice qui sopra mostra lo scheletro dei metodi delegate che implementeremo per completare la class Wrapper.&lt;/p&gt;
&lt;p&gt;Come anticipato, la nostra class estende UITextField e adotta il protocol delegate UITextFieldDelegate. Abbiamo anche aggiunto due variabili locali che contengono due closure opzionali personalizzate. Rispettivamente:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;La closure &lt;strong&gt;textFieldChangedHandler&lt;/strong&gt; verrà invocata ogni volta che la UITextField cambia.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;La closure &lt;strong&gt;onCommitHandler&lt;/strong&gt; verrà invocata al termine dell'editing, alla pressione del tasto Invio.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Vediamo ora, passo per passo, le singole implementazioni dei metodi che aggiungeremo alla nostra class.&lt;/p&gt;
&lt;h4 id=&quot;textfield-shouldchangecharactersinrange-replacementstring&quot;&gt;textField:shouldChangeCharactersInRange:replacementString:&lt;/h4&gt;
&lt;p&gt;Il metodo delegate shouldChangeCharactersInRange:replacementString: viene invocato automaticamente dal sistema ogni volta che scriviamo qualcosa con la tastiera. Ci permette di eseguire controlli sul contenuto, restituendo un valore booleano a seconda che il contenuto inserito sia permesso o meno dalle nostre regole di validazione.&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;Copia&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;Nel nostro caso basterà comporre la nuova stringa risultante dall'inserimento dell'input dell'utente e di quella attualmente presente nella UITextField. Per semplicità convertiamo il tipo String in un NSString di Foundation, che offre tutti gli strumenti per comunicare direttamente con l'oggetto NSRange fornito come parametro di input dal metodo.&lt;/p&gt;
&lt;p&gt;Una volta convertita la stringa, applichiamo la trasformazione proposta dal metodo:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;replacingCharacters(in: range, with: string)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;passando come parametri i due valori forniti in input dal metodo: range e la stringa inserita dall'utente. Il risultato sarà la composizione tra l'input dell'utente e il contenuto attuale della UITextField.&lt;/p&gt;
&lt;p&gt;Questo valore sarà quello che passeremo in input alla closure definita in precedenza:&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;L'implementazione di questo metodo, richiamato dal sistema al termine della fase di editing, è molto semplice: dovrà solo invocare la closure personalizzata definita prima. In questo modo potremo eseguire un blocco di codice arbitrario ogni volta che l'editing termina.&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;Copia&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;L'ultimo metodo da implementare è textFieldShouldReturn. La sua implementazione ci permetterà di costruire un meccanismo molto semplice per spostare il focus dal nostro TextField ad altre class simili contenute nella stessa container view. Vediamo come funziona.&lt;/p&gt;
&lt;p&gt;La prima cosa che facciamo è chiedere all'elemento textField corrente un riferimento alla propria superview?.superview?, seguendo uno schema simile a quello rappresentato nel diagramma seguente:&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;Diagramma di una VStack che contiene due view SATextField, ciascuna con una WrapperView all'interno, con frecce .superView? che risalgono al 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;Se viene restituito un oggetto valido, invochiamo il suo metodo viewWithTag, passando il tag corrente incrementato di uno. In questo modo siamo riusciti a creare un meccanismo di navigazione molto elementare, che permette di risalire fino al container e chiedergli altre view con un tag specifico.&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;Copia&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;Se il valore restituito esiste ed è di tipo UITextField, abbiamo trovato un'altra UITextField e possiamo passarle il controllo. Altrimenti chiudiamo semplicemente la tastiera.&lt;/p&gt;
&lt;p&gt;La nostra class Wrappable è pronta. Ora non resta che collegarla a SwiftUI.&lt;/p&gt;
&lt;h3 id=&quot;uiviewrepresentable&quot;&gt;UIViewRepresentable&lt;/h3&gt;
&lt;p&gt;SwiftUI mette a disposizione un protocol molto utile, chiamato UIViewRepresentable, che permette di esporre tutti quegli oggetti UIKit che finora non sono stati integrati nativamente in SwiftUI.&lt;/p&gt;
&lt;p&gt;Adottando questo protocol è possibile costruire un oggetto che espone nativamente a SwiftUI il contenuto di una UIView. Richiede di implementare solo due metodi:&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;Copia&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;Il primo metodo si occupa di creare la nostra UIView e di fornirla a SwiftUI in un formato some View compatibile, ammesso dal protocol di SwiftUI come abbiamo visto nei tutorial precedenti.&lt;/p&gt;
&lt;p&gt;Il secondo metodo verrà invocato ogni volta che la nostra UIView deve essere aggiornata per riflettere un cambiamento nell'interfaccia utente (un po' come la property body che abbiamo visto negli oggetti nativi di SwiftUI).&lt;/p&gt;
&lt;p&gt;Infine aggiungiamo al nostro oggetto alcune variabili locali che useremo per guidare il comportamento della class WrappableTextField dichiarata in precedenza:&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;Copia&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;Queste variabili saranno i parametri richiesti per creare l'oggetto SwiftUI. Verranno passate alla class Wrapper istanziata prima ed esprimono, rispettivamente: il valore del tag da associare al TextField, le closure necessarie per gestire i cambiamenti dell'input dell'utente e la fine dell'editing, e il valore da associare al placeholder della nostra UITextField.&lt;/p&gt;
&lt;p&gt;Il contenuto del metodo makeUIView associa semplicemente i parametri inseriti dall'utente durante la creazione dell'oggetto SwiftUI ai parametri corrispondenti esposti dalla class WrappableTextField.&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;Copia&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;Il metodo updateUIView imposta la hugging priority della nostra UITextField in modo che si adatti a tutto lo spazio disponibile nel Container View, in modo coerente con tutti gli altri oggetti:&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;Copia&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;mettiamo-tutto-insieme-un-esempio-reale&quot;&gt;Mettiamo tutto insieme: un esempio reale&lt;/h3&gt;
&lt;p&gt;Proviamo a usare il nostro nuovissimo SATextField in un esempio pratico:&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;Copia&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;Fatto, ragazzi! Con poche righe di codice abbiamo creato un oggetto TextField che risponde ai cambi di focus e al completamento dell'editing, in attesa che la prossima beta di iOS13 risolva i problemi attuali dell'oggetto TextField nativo.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://www.sofapps.it/blog/textfield-uiviewrepresentable/fig-2.gif&quot; alt=&quot;Registrazione dello schermo su iPhone dei due campi di testo personalizzati, in rosso, con i placeholder @username e @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>Un gioco TicTacToe in SwiftUI</title>
    <link href="https://www.sofapps.it/it/blog/tictactoe-swiftui/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Il post costruisce in SwiftUI beta un TicTacToe Uomo contro Macchina in meno di 160 righe. Il model Square pubblica i cambiamenti tramite un PassthroughSubject di Combine, la SquareView li osserva con @ObjectBinding e un flag @State governa l'alert di fine partita in ContentView.</summary>
    <content type="html">&lt;p&gt;Oggi proviamo a costruire un gioco TicTacToe in meno di 160 righe con SwiftUI, il nuovo framework dichiarativo di Apple che promette di sostituire nel prossimo futuro il suo fratello UIKit. Apriamo Xcode.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In queste ore sono uscite la beta 2 di Xcode e quella di macOS Catalina. Vi consiglio caldamente di installarle entrambe: abbiamo notato un netto miglioramento generale delle prestazioni e una maggiore reattività di Xcode sotto ogni aspetto.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Una volta aperto Xcode, creiamo un nuovo progetto chiamato TicTacToe e controlliamo che la spunta su SwiftUI sia attiva. Premiamo next e scegliamo una cartella in cui salvare il progetto.&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;Finestra di nuovo progetto di Xcode con il nome prodotto TicTacToe e la casella Use SwiftUI attiva&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;Terminata l'inizializzazione, Xcode mostra lo scheletro del progetto pre-generato. Passiamo a ContentView.swift e iniziamo subito a dare forma alla logica del gioco.&lt;/p&gt;
&lt;p&gt;Nel TicTacToe due avversari si sfidano su una scacchiera 3x3, ciascuno con il proprio segno, X oppure O. Vince chi per primo allinea tre segni uguali in orizzontale, in verticale o in diagonale.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;La prima cosa da fare, quindi, è creare un model che rifletta quanto appena detto.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Scriviamo un enum che rappresenti lo stato di una casella. Può essere vuota, occupata da noi o dal 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;Copia&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;Per giocare ci serve una scacchiera 3x3. Proviamo quindi a definire il model di una singola casella:&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;Copia&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;La classe Square adotta il protocollo &lt;strong&gt;BindableObject&lt;/strong&gt;. Gli oggetti che adottano questo protocollo notificano i subscriber nel framework SwiftUI quando una o più delle loro proprietà cambiano.&lt;/p&gt;
&lt;p&gt;Per farlo bisogna adottare correttamente il protocollo, aggiungendo un'istanza che pubblica un evento quando l'oggetto cambia. Questa istanza si chiama 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;Copia&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 è una classe messa a disposizione dal framework Combine che ci permette di pubblicare una notifica a tutti i richiedenti. La notifica ha due parametri: l'output e un eventuale errore.&lt;/p&gt;
&lt;p&gt;Per ora vogliamo solo avvisare tutti che qualcosa è cambiato nell'oggetto Square. Poiché nessuno dei due parametri ci interessa, passiamo Void come primo e Never come secondo. Il primo indica che non passiamo alcun output, il secondo che non c'è possibilità di errore.&lt;/p&gt;
&lt;p&gt;Definiamo poi la proprietà status della nostra casella e, al suo interno, aggiungiamo un meccanismo che invia una notifica quando ne cambiamo il valore:&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;Copia&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;Possiamo passare adesso al Model vero e proprio che descrive il gioco e la scacchiera. Lo chiameremo 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;Copia&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;Cominciamo dichiarando la variabile array che conterrà le singole caselle della scacchiera. Nella funzione init aggiungiamo 9 elementi di tipo Square, tutti con status .empty&lt;/p&gt;
&lt;p&gt;A fine partita ci servirà un metodo per riportare il gioco allo stato iniziale:&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;Copia&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;Ora serve un modo per controllare se la partita è finita.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Una partita finisce quando non ci sono più caselle libere oppure quando uno dei due giocatori allinea tre simboli prima dell'altro.&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;Copia&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;La variabile getter thereIsAWinner controlla semplicemente tutte le combinazioni vincenti:&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;Copia&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;La funzione checkIndex prende in input un array di interi (gli indici) e restituisce un SquareStatus opzionale: .home o .visitor se c'è un vincitore, nil altrimenti:&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;Copia&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;Ci serve un modo per fare una mossa. Per il giocatore umano controlliamo se la casella selezionata è vuota. Se lo è, ne cambiamo lo status in .home&lt;/p&gt;
&lt;p&gt;Dato che implementiamo solo una partita Uomo contro Macchina, alla fine dobbiamo anche far partire la mossa del 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;Copia&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;La mossa dell'intelligenza artificiale è davvero semplice: si estrae un indice a caso, si controlla se la casella è vuota e, in caso affermativo, la si riempie con il flag .visitor.&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;Copia&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;Ora che il model è pronto, dobbiamo interagire con SwiftUI per costruire una View che rispetti il model Square. Chiamiamola 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;Copia&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;Prima di tutto aggiungiamo il property wrapper @ObjectBinding davanti al datasource Square.&lt;/p&gt;
&lt;p&gt;In questo modo diciamo a SwiftUI che la SquareView è interessata alle notifiche di cambiamento del model. Quando ne arriverà una, SwiftUI farà calcolare automaticamente un nuovo body alla SquareView.&lt;/p&gt;
&lt;p&gt;Dentro il body controlliamo se lo status è diverso da .empty. In tal caso scriviamo X oppure O a seconda del giocatore.&lt;/p&gt;
&lt;p&gt;.frame, .background e .padding sono solo ritocchi estetici della casella.&lt;/p&gt;
&lt;p&gt;Infine dobbiamo modificare la ContentView per ospitare la scacchiera, creando a questo scopo una variabile private che chiamiamo 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;Copia&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;Definiamo anche una proprietà @State per sapere se la partita è finita: deve essere @State perché vogliamo aggiornare il body della ContentView una volta terminato il gioco.&lt;/p&gt;
&lt;p&gt;Poiché ogni SquareView è identica e il suo comportamento cambia solo in base all'indice, definiamo anche un metodo buttonAction:&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;Copia&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;In questo modo ogni SquareView invoca il metodo con il proprio indice e viene eseguito il codice relativo alla posizione indicata.&lt;/p&gt;
&lt;p&gt;Infine possiamo costruire il body completo, che riflette le 9 SquareView (3 righe da 3):&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;Copia&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;Un'ultima cosa riguarda il feedback per l'utente: vogliamo avvisarlo con un popup quando la partita finisce o quando qualcuno vince.&lt;/p&gt;
&lt;p&gt;Per farlo possiamo usare il View modifier .presentation. Nella sua forma più semplice accetta:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un booleano condizionale che decide se mostrarlo o no&lt;/li&gt;
&lt;li&gt;Un parametro message con un Text per il corpo dell'alert&lt;/li&gt;
&lt;li&gt;Un dismissButton: con un 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;Copia&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;Ed è tutto! Come promesso, in meno di 160 righe di codice abbiamo un TicTacToe perfettamente funzionante. Se facciamo Build and Run, la nostra applicazione apparirà così:&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;L'app TicTacToe in esecuzione su iPhone simulator, con una griglia di nove caselle grigie tre per tre&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 e Sidecar</title>
    <link href="https://www.sofapps.it/it/blog/ipados-catalyst-sidecar/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Dopo una settimana di prova con un iPad Pro, l'autore conclude che non può sostituire il suo MacBook Pro per lo sviluppo, anche se per appunti, email e scrittura funziona molto bene. Il vero cambiamento sta nel software: iPadOS, Catalyst e Sidecar mostrano la visione Apple della convergenza tra dispositivi senza portare il touch sul Mac. Il post li legge come l'inizio di un cambio di abitudini per chi dipende ancora dal desktop tradizionale.</summary>
    <content type="html">&lt;p&gt;Avevo deciso di non parlare ed esprimere commenti sul nuovo iPad Pro sin dalla sua prima uscita. In fondo, pensavo si trattase dell’ennesima mossa commerciale di una Apple con al comando Tim Cook – abile uomo d’affari e solo lontanamente visionario – che mira al profitto ed alla vendita in un segmento commerciale oramai saturo. No, parlarne avrebbe solo alimentato il brusio dei blogs e dei fanatici, in un modo o nell’altro.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mi sbagliavo. Questo prodotto merita tutta la nostra attenzione per una serie di ragioni che proverò a raccontarvi.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Andiamo per ordine. Il mercato dei tablet è saturo ed in discesa vertiginosa. KGI, sostiene che insieme ad iPhone contribuirà ad un calo mai visto, durante il periodo 2016/2020, delle vendite di dispositivi iOS. Sarà anche vero, ma questo non significa che non ci sia spazio per innovare.&lt;/p&gt;
&lt;p&gt;Probabilmente l’utente medio coglierà queste innovazioni con ritardo o forse non le coglierà proprio, ma questo non significa che a Cupertino non stiano provando ad innovare. Quello che ci si aspetta da un Tablet – e che Phil Schiller ha teatralmente raccontato durante la presentazione del 21 Marzo 2016 – è l’abilità di rimpiazzare in tutte le attività quotidiane i nostri vecchi personal computer. Apple sostiene dalla prima introduzione di iPad Pro che il nuovo iPad è il sostituto ideale del «noioso» PC anni ‘80. Meglio, è l’interpretazione in chiave moderna del modo di esprimersi, creare, studiare e divertirsi. Sarà vero?&lt;/p&gt;
&lt;p&gt;Approfittando delle novità presentate alla WWDC 2019, ho deciso di effettuare un test approfondito con un iPad Pro per capirne lo stato dell’arte e quanto la proposizione di cui sopra sia vicina alla realtà. Non ho usato la tastiera venduta come accessorio per una semplice ragione: si può usare solo in una posizione forzata (quindi niente scrittura estrema sul divano o nel letto) e costa uno sproposito. Per questa mia settimana di prova ho deciso di usare una molto più performante e confortevole tastiera Apple bluetooth; ho la libertà di muovermi e mettermi come e dove voglio. Oltretutto, quando sono in mobilità non vedo proprio cosa potrei farmene di una tastiera fisica in generale.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Apple pencil, invece, è spettacolare. L’uso della matita è così radicato nella nostra cultura moderna che usarne una con un iPad risulterà quasi più naturale delle dita stesse (per alcune attività le dita continuano ad essere superiori in termini di efficacia e riscontro).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anche la nuova revisione della penna ha fatto passi da gigante rispetto alla prima versione che aveva un cappuccio per nascondere il jack di ricarica praticamente perso prima ancora di aprire la confezione, nessun alloggiamento dove conservare la penna nell’iPad con sicurezza e, tralascerei volentieri questo dettaglio, un meccanismo di ricarica davvero controverso.&lt;/p&gt;
&lt;p&gt;Sicuramente siamo ad un punto di svolta, ma dire che il nuovo iPad è un sostituto del personal computer è quantomeno una forzatura. Il mio mestiere è scrivere applicazioni oltre che coordinare un team di sviluppatori. Tutte operazioni che definisco «complesse» non per il loro contenuto, ma per la modalità di espletarle. Immaginate una giornata tipo con un centinaio di email a cui rispondere, una ventina di telefonate su cui prendere appunti, due o tre progetti Xcode aperti su cui fare revisione del codice ed una infinità di documenti da consultare, annotare e scrivere. Sono assolutamente convinto che questo mestiere sia dannoso per la propria salute mentale e fisica, ma oramai è troppo tardi per cambiare rotta ed in fondo, mi piace molto.&lt;/p&gt;
&lt;p&gt;Chiaramente, con queste premesse, l’iPad Pro non può assolutamente essere un sostituto del mio MacBook Pro: ci sono troppe cose che risultano più macchinose e meno precise. Così come ci sono operazioni che risultano estremamente semplici, veloci ed efficaci. Prendere appunti, rispondere alle email, scrivere quest’articolo e comunicare è di una semplicità disarmante.&lt;/p&gt;
&lt;p&gt;Non fraintendetemi, non è un discorso di potenza: il nuovo iPad ne ha da vendere e basta fare una piccola ricerca per vedere l’esplosione rigogliosa di centinaia di comparazioni di potenza tra iPad e Macbook. Siamo davanti ad un gioiello, in termini di tecnologia, che non ha nulla da invidiare ad un portatile di fascia alta.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Fortunatamente per noi, il problema è un altro. È evidente che iOS per come lo conosciamo mostra i suoi limiti. Per chi ha avuto modo di usare e lavorare con la prima versione di iOS non potrà che notare gli incredibili cambiamenti e sforzi che sono stati fatti negli anni. iOS7 ha cambiato il nostro modo di pensare le interfacce; iOS8 ci ha mostrato che non è una questione di quante applicazioni riesci a tenere aperte in contemporanea ma di come le fai dialogare tra loro; iOS9 ha consolidato la comunicazione tra dispositivi rendendo un piacere per la mente il passaggio da un dispositivo all’altro. iOS 10, 11 e 12 sono stati un continuo affinare dettagli di stabilità , stilistici, di usabilità e di esperienza che pochi altri nel mondo del software hanno avuto il coraggio di fare in un periodo così lungo: ci vuole coraggio a non inondare ogni nuovo rilascio del sistema operativo con funzionalità poco testate, poco usabili e poco studiate.&lt;/p&gt;
&lt;p&gt;Mancava ancora qualcosa per chiudere il cerchio. Questo qualcosa Microsoft ha provato, a suo modo, a rappresentarlo con Windows 10 e Microsoft Surface. Google prova a rappresentarlo da anni con il concetto di un web (e di un browser) confluente in cui è possibile fare tutto, aspettando che arrivi Fuchsia.&lt;/p&gt;
&lt;p&gt;Apple, invece, con una mossa a sorpresa, ha mostrato la sua visione della tanto agognata convergenza tra i dispositivi. Sto parlando di iPadOS e di 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;Un relatore sul palco della WWDC accanto alla slide Project Catalyst, con l'icona arancione di finestre sovrapposte a un 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;Essere una grande azienda non è facile. Ti confina dietro una difficile posizione in cui tutti si aspettano sempre “qualcosa in più”. Apple, dunque, doveva rendere questo concetto in maniera diversa — Think different, direbbe qualcuno.&lt;/p&gt;
&lt;p&gt;Nessun utente Apple si sarebbe accontentato di avere il desktop e la barra di Finder sul proprio iDispositivo. D’altronde si sa, gli utenti Apple sono un pò più esigenti e creativi.&lt;/p&gt;
&lt;p&gt;E così, ecco arrivare iPadOS. Non è un nuovo sistema operativo ma, semplicemente, una estensione di quell’iOS che oramai siamo stati abituati ad usare ed amare. Estensioni che ne abilitano funzionalità nuove e mai viste: Multitasking, Desktop e funzionalità di interconnessione che tutti avevamo solo sognato. Dando un occhiata da vicino alle API disponibili con iOS13, si nota che ci sono un’infinità di nuove risorse per creare drivers e meccanismi di comunicazione ed interfaccia USB. Fantastico.&lt;/p&gt;
&lt;p&gt;Non credo ci sarà una convergenza piatta e scontata come quella che ci ha mostrato e raccontato Microsoft. Non credo che succederà mai che lo schermo del mio Macbook diventi touch. Allo stesso tempo, però, vedo che portare un’applicazione nativa su macOS da iPad è un gioco da ragazzi e che lo schermo del mio iPad può diventare quella superficie tattile tanto desiderata con cui colloquiare con il proprio computer attraverso 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;Una donna in biblioteca disegna con Apple Pencil su un iPad accanto a un MacBook Pro, entrambi con la stessa illustrazione di una balena (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, proverà a mostrare come lo stile e la visione d’insieme, prima di tutto, possano essere il principio di un cambiamento sottile ed elegante, ma non per questo meno efficace, al nostro modo di dialogare con le macchine.&lt;/p&gt;
&lt;p&gt;A mio personale modo di vedere, questo giugno la WWDC ha presentato davvero tante grandi novità, tra queste l’introduzione di iPadOS, Continuity e Catalyst.&lt;/p&gt;
&lt;p&gt;Sarà probabilmente un evento che resterà nella storia e che segnerà un passaggio epocale per tutti quelli che hanno ancora bisogno del vecchio desktop e della barra di Finder per lavorare. Se non mi credete, provate a collegare una tastiera al nuovo iPad Pro e premete ⌘+Tab.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Programmare con SwiftUI</title>
    <link href="https://www.sofapps.it/it/blog/swiftui-programming/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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 è la risposta di Apple ai framework dichiarativi e reattivi diffusi sul web e nello sviluppo mobile. Al posto dei controller che fanno da mediatori tra view e model, si descrivono uno stato e una view che ne deriva, e SwiftUI ricostruisce l'interfaccia quando lo stato cambia. Questo post apre una serie di appunti di studio sul framework.</summary>
    <content type="html">&lt;p&gt;SwiftUI segna senza dubbio l'inizio di una nuova era nella storia della programmazione Apple. Negli ultimi anni abbiamo visto moltiplicarsi i framework basati sull'idea di interfacce dichiarative e di programmazione reattiva. Il web ne è l'esempio più evidente, ma non mancano casi importanti anche nello sviluppo mobile. Siamo continuamente bombardati da messaggi di marketing secondo cui:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;mantenere un'unica codebase per tutte le piattaforme è il modo migliore per aumentare la produttività aziendale e offrire soluzioni efficaci ai nostri clienti.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;React Native (Facebook) e Flutter (Google) sono un ottimo esempio di questa proposta. Non è lo scopo di questo articolo confrontare queste tecnologie: ho citato i due esempi per mostrare come la tendenza del software negli ultimi anni stia andando in direzioni diverse da quelle a cui siamo stati abituati finora.&lt;/p&gt;
&lt;p&gt;I nostri dispositivi sono sempre più potenti, e questa potenza trova il suo posto naturale in interfacce e paradigmi di interazione sempre più sofisticati e complessi. L'anno scorso &lt;a href=&quot;https://blog.prototypr.io/iphone-x-and-peripheral-vision-813b2599bf8c&quot;&gt;ho scritto un pezzo&lt;/a&gt; sull'uscita di iPhone X e sulla sensazione di fluidità che questo nuovo dispositivo, insieme alle ultime scelte stilistiche di iOS 11 e 12, mi aveva lasciato.&lt;/p&gt;
&lt;p&gt;Animazioni morbide, continue e coerenti, gesture integrate nell'esperienza di navigazione. Sono solo alcuni esempi di ciò che voglio dire: l'asticella delle aspettative si è alzata ancora una volta, e queste novità non si esprimono facilmente con un framework tradizionale.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;La natura discreta dei linguaggi imperativi fatica a reggere il confronto con il senso di continuità e fluidità imposto dai nuovi paradigmi di interfaccia.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Apple è sempre stata un'azienda molto conservatrice (Objective-C continua a funzionare e a compilare benissimo) per quanto riguarda i suoi ambienti di sviluppo e, in generale, l'intero ecosistema.&lt;/p&gt;
&lt;p&gt;L'introduzione di Swift cinque anni fa, con i suoi nuovi paradigmi e il suo slancio di modernità, era già stato un grande segnale di cambiamento da parte di Cupertino. Ma era chiaro che non bastava. Così, a sorpresa per tutti, arriva la risposta di Apple agli altri giganti del 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 con il file ContentView.swift, che contiene una VStack e una HStack di Text, e l'anteprima live con il testo 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 è un framework dichiarativo orientato ai componenti. Dimentichiamo quindi il pattern MVC, in cui i controller facevano da mediatori tra view e model. In SwiftUI abbiamo solo uno stato e una view derivata dallo stato. Non appena lo stato cambia, SwiftUI ricostruisce l'interfaccia tenendo conto delle modifiche.&lt;/p&gt;
&lt;p&gt;In una serie di post cercherò di condividere i miei pensieri e i miei appunti di viaggio personali durante lo studio di questo framework nuovo e, per certi versi, misterioso.&lt;/p&gt;
&lt;p&gt;Ho pensato che potesse essere utile, nella speranza che sia un punto di partenza per imparare qualcosa di nuovo e davvero entusiasmante.&lt;/p&gt;
&lt;p&gt;Happy Coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>WWDC18: ARKit 2, confronto delle prestazioni del tracking 2D</title>
    <link href="https://www.sofapps.it/it/blog/arkit2-image-tracking-performance/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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 introduce ARImageTrackingConfiguration, che traccia le immagini 2D in tempo reale e gestisce le immagini che escono dall'inquadratura, mentre iOS 11 offre solo ARWorldTrackingConfiguration con un tracking meno preciso. L'articolo costruisce una piccola app che sovrappone testo ai biglietti da visita, aggiunge un workaround basato su un timer per rimuovere i nodi rimasti su iOS 11 e carica le immagini di riferimento da un JSON remoto. Segnala anche un bug di Xcode 10 che impedisce di rilevare le immagini sui dispositivi con iOS 11.</summary>
    <content type="html">&lt;p&gt;Uno dei trend tecnologici più interessanti dell'ultimo anno è stato di sicuro la realtà aumentata. Tutti i grandi nomi hanno fatto qualcosa in proposito, Apple compresa, che ha investito molte risorse e molto tempo su questo tema e, come ha detto Tim Cook:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…la realtà aumentata potrebbe essere la prossima grande novità…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Se il 2017 è stato l'anno della pietra miliare, con l'introduzione di un framework completo per l'AR, il 2018 è senza dubbio l'anno della maturità di questa tecnologia, grazie ad ARKit 2.&lt;/p&gt;
&lt;p&gt;Molte cose sono cambiate a favore di usabilità, manutenibilità e semplicità: tutti aspetti che possono aiutare molto a diffondere una tecnologia presso il grande pubblico. Il resto dell'articolo racconta la mia esperienza personale con il nuovo framework ARKit, sottolineando miglioramenti e differenze tra iOS 11 e iOS 12. Come in ogni buon articolo per sviluppatori, serve un caso di studio su cui lavorare per spiegare meglio l'argomento. Partiamo da questo.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Creeremo una semplice applicazione che usa la realtà aumentata per mostrare offerte speciali e informazioni aggiuntive quando si inquadrano dei biglietti da visita.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Opzionalmente, l'applicazione caricherà le informazioni necessarie da un JSON remoto e mostrerà poi all'utente i relativi arricchimenti visivi quando servono.&lt;/p&gt;
&lt;p&gt;Per prima cosa apriamo Xcode e creiamo un nuovo progetto AR, compilando tutti i campi richiesti:&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;Il selettore dei template di Xcode con Augmented Reality App selezionato tra le applicazioni iOS&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;Per impostazione predefinita Xcode crea una scena iniziale del tutto inutile ai fini di questo articolo. Eliminiamola e apriamo il file ViewController.swift creato automaticamente.&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;Finestra di dialogo di Xcode che chiede se spostare art.scnassets nel Cestino o rimuovere solo il riferimento&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;Dato che la scena generata automaticamente non ci interessa più, modifichiamo di conseguenza il metodo viewDidLoad. Ci basta assegnare all'outlet sceneView l'istanza giusta come delegate, più qualche opzione utile per il debug.&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;Copia&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;La classe ARSCNView è il punto di ingresso di qualsiasi app AR. Combina i contenuti virtuali con il mondo reale visto attraverso la fotocamera del dispositivo e si occupa anche di molte altre cose interessanti, come mappare i tocchi sulle coordinate del mondo reale. ARSCNView usa un approccio basato su delegate: implementando il suo ARSCNViewDelegate possiamo aggiungere contenuti virtuali a qualsiasi oggetto reale che ARKit rileva automaticamente, quasi per magia.&lt;/p&gt;
&lt;p&gt;Come si intuisce, ARKit è il framework responsabile della realtà aumentata. Per funzionare va prima inizializzato correttamente. Aggiungiamo un metodo che lo faccia:&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;Copia&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;Il metodo resetTrackingConfiguration si occupa di creare e avviare una ARSession che funzioni correttamente, a partire da una ARConfiguration.&lt;/p&gt;
&lt;p&gt;ARSession è un oggetto condiviso (singleton) che gestisce la fotocamera del dispositivo e i sensori di movimento, per darci un'esperienza di realtà aumentata completa. I movimenti della camera vengono fusi con i dati dei sensori di inclinazione e di spostamento e con quelli degli altri sensori, in modo da orientare in maniera rapida e coerente il mondo artificiale dentro l'applicazione. L'istanza di ARSCNView creata dallo storyboard contiene già un riferimento alla ARSession condivisa predefinita, quindi non dobbiamo inizializzarla: ci basta creare una ARConfiguration valida.&lt;/p&gt;
&lt;p&gt;ARConfiguration è una classe astratta e non la usiamo direttamente. Useremo invece istanze di ARWorldTrackingConfiguration e di ARImageTrackingConfiguration, che ne sono implementazioni concrete. Ce ne sono altre che si occupano solo di tracciare l'orientamento del dispositivo (AROrientationTrackingConfiguration) oppure i volti e le espressioni facciali (ARFaceTrackingConfiguration), ma non sono rilevanti per questa discussione.&lt;/p&gt;
&lt;p&gt;ARWorldTrackingConfiguration è la classe principale per le sessioni di world tracking. Introdotta con iOS 11, è in grado di rilevare e tracciare molti elementi interessanti del mondo reale, tra cui oggetti 3D, piani infiniti e immagini 2D. Sono le immagini 2D quelle che interessano a noi; tuttavia iOS 12 introduce una nuova specializzazione della classe astratta ARConfiguration, chiamata ARImageTrackingConfiguration.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Come la sua predecessora, è in grado di tracciare immagini 2D, ma con parecchi miglioramenti, come il tracking in tempo reale e la gestione automatica del caso in cui l'immagine esce dall'inquadratura. Ci torneremo tra poco.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dato che vogliamo supportare sia iOS 11 sia iOS 12 per poterne confrontare le prestazioni, dobbiamo prevedere configurazioni personalizzate per entrambe le versioni. Se iOS 12 è disponibile, useremo la nuova implementazione di ARConfiguration:&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;Copia&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;altrimenti useremo quella standard:&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;Copia&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 entrambi i casi diciamo alla sessione condivisa di usare la configurazione appena costruita, per tutto il resto della discussione:&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;Copia&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;Ora che abbiamo configurato correttamente la ARSession, ci servono delle immagini da dare in pasto al motore di tracking della ARCamera. Selezioniamo gli Assets del progetto:&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;Il navigatore di progetto di Xcode con il progetto ARWorld e Assets.xcassets selezionato&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;e con il tasto destro nella colonna di sinistra creiamo un nuovo 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;Il menu contestuale dell'asset catalog con New AR Resource Group evidenziato&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;Chiamiamolo Photos e aggiungiamo qualche biglietto. La cosa più importante qui è indicare per ogni biglietto le dimensioni reali stimate: il motore 3D ha bisogno di questa informazione per stimare correttamente l'oggetto nel mondo 3D.&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;Un AR Resource Group con due immagini di riferimento, card1 e card2, e i campi delle dimensioni di card1 espressi in metri&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;Come si vede, uno dei biglietti ha un'icona di avviso. Clicchiamoci sopra:&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;L'avviso di Xcode per card2: l'istogramma è stretto e l'immagine ha poco contrasto locale&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 ci avverte che l'istogramma e i contrasti del biglietto non sono ottimali per il riconoscimento dell'immagine. Per il momento ignoriamolo.&lt;/p&gt;
&lt;p&gt;La nostra app di prova deve poter tracciare immagini 2D e associarle a oggetti del mondo reale tramite gli anchor. ARAnchor è la classe che rappresenta posizione e orientamento nel mondo reale, mappando l'oggetto rilevato in una scena AR. Tra le altre proprietà contiene una matrix_float4x4 che definisce rotazione, traslazione e scala dell'anchor nelle coordinate del mondo.&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;Copia&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;Quando si usa una ARWorldTrackingConfiguration o una ARImageTrackingConfiguration, ARKit crea automaticamente gli anchor corrispondenti ogni volta che trova nella scena una corrispondenza con le nostre immagini di riferimento. Dobbiamo solo implementare il relativo delegate, per aggiungere al nuovo anchor l'oggetto corrispondente sotto forma di 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;Copia&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 è il mattoncino base di tutte le app AR. Unisce le coordinate 3D con gli oggetti della scena, come luci, camera e altri contenuti visualizzabili. Come per le UIView, gli SCNNode seguono una gerarchia ad albero che permette di annidarli con semplici primitive come&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;Copia&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;Il metodo renderer:nodeFor: viene chiamato ogni volta che viene rilevata una nuova corrispondenza tra il nostro insieme di immagini e il mondo reale. Dato che viene chiamato anche per qualsiasi nuovo ARAnchor aggiunto alla scena (piani rilevati, oggetti 3D e così via), conviene verificare che si tratti di un ARImageAnchor per essere sicuri che tutto funzioni come previsto:&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;Copia&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;poi creiamo un nuovo SCNNode che conterrà tutto il necessario e facciamo uno switch sul nome dell'immagine rilevata: è la logica principale che distingue le immagini del nostro 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;Copia&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;infine, se riusciamo a creare un nodo valido, lo aggiungiamo alla gerarchia e restituiamo il nodo principale:&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;Copia&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;Per dare un tocco professionale, vogliamo aggiungere animazioni di fade in e fade out a tutto il flusso. Dato che renderer:nodeFor: viene chiamato sul main thread, conviene eseguire runAction in modo asincrono, per essere certi di non avere animazioni scattose.&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;Copia&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;per-i-piu-curiosi&quot;&gt;Per i più curiosi&lt;/h2&gt;
&lt;p&gt;addLabel è un metodo di supporto che genera un oggetto SpriteKit 2D valido. Dato che lavoriamo con immagini 2D tracciate, vogliamo aggiungere alla scena dei contenuti virtuali 2D, per dare all'utente la sensazione che le informazioni aggiuntive compaiano proprio sopra l'oggetto reale.&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;Copia&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;Per prima cosa creiamo uno SCNPlane con le dimensioni fisiche dell'immagine rilevata. SCNPlane è un oggetto geometrico rettangolare e piatto, che ha il compito di contenere il nostro testo bidimensionale. Ma dato che siamo in un mondo 3D, dobbiamo racchiuderlo in uno 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;Copia&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;Dobbiamo anche ruotare il planeNode risultante, perché per impostazione predefinita viene generato perpendicolare alla radice. A questo punto non è ancora stato creato nessun oggetto 2D né alcun testo: per farlo ci serve una scena SpriteKit.&lt;/p&gt;
&lt;p&gt;SKScene è l'equivalente di SCNScene nel mondo 2D gestito da SpriteKit. Rappresenta il contenuto di una scena 2D e da sola non ha nulla da mostrare, perché, come la sua gemella 3D, è solo un contenitore. Per generare il testo 2D useremo SKLabelNode, che funziona in modo molto simile alla UILabel di UIKit: si configurano testo, font e altri parametri in modo molto diretto.&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;Copia&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;Purtroppo non c'è un supporto nativo per andare a capo su più righe con il carattere di ritorno a capo (\n), quindi dobbiamo ricrearlo a mano. Per farlo usiamo una semplice tokenizzazione della stringa originale.&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;Copia&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;La parte più interessante è come mappiamo il contenuto SpriteKit 2D nel mondo 3D. Per riuscirci usiamo SCNMaterial, la classe che definisce l'aspetto di una geometria 2D quando viene renderizzata in un mondo 3D. Come in ogni motore 3D, la nostra SCNScene ha luci e materiali che reagiscono ad esse in fase di rendering. Ci basta indicare al nostro SCNMaterial che vogliamo usare come materiale il contenuto della SKScene creata prima.&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;Copia&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;La proprietà isDoubleSided è impostata a false, perché non ci interessa il lato posteriore del nostro testo. La proprietà diffuse è di tipo SCNMaterialProperty, un semplice contenitore per la texture del materiale. Per fortuna può contenere quasi qualsiasi cosa, compresa un'intera SKScene. Alla fine diciamo al piano creato prima di usare come sorgente il materiale personalizzato appena preparato.&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;Copia&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;Se avete seguito tutto quello che abbiamo fatto finora ed eseguite il progetto su iOS 12, tutto funzionerà alla perfezione e resterete colpiti da un tracking 2D preciso e convincente. Se invece eseguite lo stesso codice su iOS 11, resterete delusi dalle prestazioni di tracking, piuttosto scarse.&lt;/p&gt;
&lt;p&gt;Inoltre c'è un bug davvero fastidioso che lascia per sempre nel mondo 3D le immagini 2D rilevate. Se ricordate, all'inizio dell'articolo ho scritto che&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;una delle novità più interessanti di ARImageTrackingConfiguration è la nuova gestione degli oggetti che scompaiono dallo schermo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dato che su iOS 11 non c'è niente del genere, dobbiamo costruirci da soli un workaround. Useremo una struct privata per tenere tutte le informazioni necessarie:&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;Copia&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;dichiarandone un array privato nel nostro ViewController. Ci serve anche un polling periodico della scena, per eliminare gli oggetti non più validi&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;Copia&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;il nostro metodo viewDidAppear si occuperà di definire il timer qui sopra&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;Copia&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;Dobbiamo solo aggiornare l'array di cache lastUpdate quando oggetti nuovi o già rilevati vengono interpretati correttamente nella scena. Per questo useremo un altro metodo delegate di 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;Copia&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;In questo modo anche su iOS 11 riusciamo a smettere di tracciare gli oggetti 2D indesiderati sullo schermo.&lt;/p&gt;
&lt;p&gt;Il progetto completo è disponibile su &lt;a href=&quot;https://github.com/valvoline/ARKit2-trackingImages&quot;&gt;Github&lt;/a&gt;. Mentre scrivo, &lt;a href=&quot;https://stackoverflow.com/questions/50863327/arworldtrackingconfiguration-does-not-work-when-deployed-from-xcode10-to-ios11-d/50864848#50864848&quot;&gt;un bug affligge Xcode 10&lt;/a&gt; e impedisce di usare le immagini del dataset quando si installa l'app su dispositivi con iOS 11.&lt;/p&gt;
&lt;p&gt;Di conseguenza, su iOS 11 l'app non rileverà nessuna immagine 2D se installata da Xcode 10. Per aggirare il problema, bisogna eseguire il progetto qui sopra con Xcode 9 quando lo si installa su un dispositivo con iOS 11, commentando i simboli sconosciuti legati ad ARImageTrackingConfiguration.&lt;/p&gt;
&lt;h3 id=&quot;caricare-i-dataset-da-remoto&quot;&gt;Caricare i dataset da remoto&lt;/h3&gt;
&lt;p&gt;Una nota finale sul caricamento dinamico del dataset. Il codice qui sopra si basa su un dataset statico, memorizzato nel progetto. Potrebbe però essere meglio caricare il dataset dinamicamente da un server remoto. Per questo ho preparato un semplicissimo esempio in JSON.&lt;/p&gt;
&lt;figure class=&quot;codeblock&quot;&gt;&lt;div class=&quot;codeblock-head&quot;&gt;&lt;span&gt;Codice&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;Copia&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;Scarichiamo questo JSON dalla nostra 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;Copia&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;e carichiamo i biglietti in modo dinamico:&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;Copia&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;anche il nostro metodo resetTrackingConfiguration va adattato per tenere conto del caricamento a 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;Copia&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;A questo punto l'app dovrebbe funzionare sia su iOS 11 sia su iOS 12, caricando dinamicamente dal server il contenuto del dataset.&lt;/p&gt;
&lt;p&gt;Buon coding!&lt;/p&gt;
&lt;h3 id=&quot;riferimenti&quot;&gt;Riferimenti&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/arkit/&quot;&gt;Pagina ufficiale di ARKit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/arkit&quot;&gt;Pagina di ARKit per sviluppatori&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: gestire l'interazione 3D e i controlli UI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Un workflow di sharing personalizzato con CloudKit</title>
    <link href="https://www.sofapps.it/it/blog/custom-cloudkit-sharing/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Il flusso standard di CKShare richiede una UICloudSharingController, un link inviato con un'app di terze parti e dei delegate lato ricevente. Questo post conserva l'URL del CKShare nel campo privateShareUrl di un record pubblico: il proprietario aggiunge i partecipanti in modo silenzioso e questi leggono il record privato dal database condiviso. Include il codice Swift per zona, record, share e fetch, e un progetto di esempio su GitHub.</summary>
    <content type="html">&lt;p&gt;CloudKit dà grande importanza alla privacy e alla sicurezza degli utenti. Poiché una delle preoccupazioni principali del mio ultimo lavoro, Lookii, riguardava proprio la privacy degli utenti, è stata un'ottima occasione per approfondire le reali potenzialità del framework.&lt;/p&gt;
&lt;p&gt;Da iOS 10 CloudKit include una funzionalità integrata per condividere dati privati tra i partecipanti di un container, chiamata CKShare. Purtroppo online ci sono pochissimi articoli sull'argomento e la documentazione di Apple non entra nel dettaglio dei temi avanzati. Tutti gli articoli che ho citato nelle note descrivono il flusso base della condivisione con CloudKit, con alcune varianti interessanti che però non si adattavano esattamente al mio caso. Non tratterò le basi, per le quali rimando alle note. Mi concentrerò invece su un workflow specifico e più avanzato, che potrebbe essere utile a qualcun altro.&lt;/p&gt;
&lt;h3 id=&quot;il-caso-d-uso&quot;&gt;Il caso d'uso&lt;/h3&gt;
&lt;p&gt;Immaginiamo di avere un'applicazione che condivide informazioni degli utenti. Alcune devono restare private ed essere condivise solo tra amici, altre invece devono essere accessibili pubblicamente a tutti i partecipanti del container.&lt;/p&gt;
&lt;p&gt;Supponiamo che il nostro tipo di CKRecord sia MyUser e contenga le seguenti informazioni pubbliche:&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;Copia&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;Altri dati non saranno pubblici, per ragioni di privacy. Per questi useremo un altro CKRecord, che chiameremo PrivateInfo, con il seguente contenuto:&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;Copia&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;Stavolta il record non farà parte del database pubblico. Verrà invece salvato in quello privato, accessibile solo al proprietario del record, e inserito in una RecordZone che sarà condivisa con i partecipanti scelti.&lt;/p&gt;
&lt;p&gt;Uno schema generale del caso d'uso descritto potrebbe essere questo:&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;Diagramma: il database pubblico con firstName, lastName, thumbnail e privateShareUrl, il database privato con phoneNumber ed email e, tra i due, la zona condivisa 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;il-workflow-generale-di-cloudkit-e-i-suoi-limiti&quot;&gt;Il workflow generale di CloudKit e i suoi limiti&lt;/h2&gt;
&lt;p&gt;Come detto, una delle preoccupazioni principali nell'usare il workflow di sharing predefinito di CloudKit riguardava le opzioni di personalizzazione della UI, molto limitate. In particolare il workflow base segue uno schema molto rigido:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chi condivide deve occuparsi di:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Creare il CKShare&lt;/li&gt;
&lt;li&gt;Passarlo a una specifica UICloudSharingController&lt;/li&gt;
&lt;li&gt;Creare un URL da condividere con app di terze parti&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Gli utenti che vogliono essere aggiunti devono:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Toccare il link per accettare l'URL condiviso&lt;/li&gt;
&lt;li&gt;Implementare alcuni delegate in UIApplication&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anche se la sua linearità lo rende facilissimo da integrare, questo approccio manca di alcune funzionalità avanzate. Per esempio, non vorrei disturbare gli utenti con flussi complicati che interrompono la naturale esperienza dell'app. Vorrei invece eseguire il workflow il più possibile in background, liberando mittente e destinatario da dialoghi inutili e da cambi di contesto tra un'app e l'altra.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sarebbe bello poter scegliere i destinatari delle mie informazioni private semplicemente toccando l'icona dell'utente nella mia app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;implementazione&quot;&gt;Implementazione&lt;/h2&gt;
&lt;p&gt;La prima cosa da fare è abilitare la userDiscoverability tra gli utenti dell'app, altrimenti il resto del processo non funzionerà a causa dei vincoli di privacy.&lt;/p&gt;
&lt;p&gt;Per fortuna Apple ha previsto un approccio molto semplice: basta una semplice richiesta di permesso all'utente, che potete inserire nelle prime fasi della vita dell'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;Copia&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;Una volta ottenuto il permesso dell'utente siamo pronti a partire. Creiamo un CKRecord utente molto semplice (quello che sarà pubblico):&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;Copia&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;Poi, come parte del processo iniziale, dobbiamo creare una zona specifica con cui esporre una vista dei nostri record privati agli utenti scelti (i nostri amici preferiti):&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;Copia&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;Infine creiamo un record privato che contiene tutte le nostre informazioni preziose:&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;Copia&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;Notate che il record è legato alla CKRecordZone creata prima.&lt;/p&gt;
&lt;p&gt;Come avrete notato, non abbiamo ancora scritto il campo privateShareUrl che fa parte del record pubblico: è la parte cruciale di tutto l'approccio descritto in questo articolo. Il comportamento standard, infatti, si basa sulla UICloudSharingController, che mostra all'utente un dialogo in cui si sceglie cosa e come condividere. Il risultato del dialogo è un URL da usare con app di terze parti come Messaggi, Mail o altro per comunicare l'intenzione di condividere qualcosa.&lt;/p&gt;
&lt;p&gt;A peggiorare le cose, dall'altra parte il destinatario deve toccare il link che a sua volta apre la nostra app e chiama il corrispondente metodo delegate di UIApplication. Quest'ultimo ci restituisce alla fine un'istanza di CKShareMetadata, che possiamo usare per leggere le informazioni condivise.&lt;/p&gt;
&lt;h2 id=&quot;il-nostro-approccio&quot;&gt;Il nostro approccio&lt;/h2&gt;
&lt;p&gt;Poiché la nostra applicazione ha già degli utenti, vorrei aggirare questo workflow usando il campo privateShareUrl come punto di ingresso per chiunque abbia bisogno di leggere le informazioni private di uno specifico utente.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Apple dichiara che l'URL di condivisione di un CKShare è stabile e non cambia a meno che non si cambi il root record associato.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Il mio piano è simulare il workflow base di sharing usando il campo privateShareUrl che abbiamo nel database pubblico per ogni utente. Questo campo conterrà l'URL originale del CKShare. In questo modo ogni utente che vuole leggere le informazioni private di uno specifico partecipante accederà all'URL e verificherà se ha il permesso di accedere ai campi privati esposti.&lt;/p&gt;
&lt;p&gt;Gli utenti che vogliono condividere le proprie informazioni private con gli amici, invece, possono semplicemente aggiungerli all'URL di condivisione, senza disturbare i destinatari con app di terze parti e messaggi. Ottimo!&lt;/p&gt;
&lt;p&gt;La prima cosa da fare è impostare un accesso predefinito pari a nessuno per le nostre informazioni private. In questo modo, nello stato iniziale, nessuno può accedere ai nostri dati privati. Solo quando aggiungiamo qualcuno alla condivisione potrà accedere ai dati. Apple dichiara che il permesso pubblico predefinito di un CKShare è già configurato su nessun accesso.&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;Copia&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;Ora, ogni volta che un utente vuole vedere le informazioni private condivise da un altro, controllerà il privateShareUrl designato per l'utente in questione:&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;Copia&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;Semplice ed efficace. Ho messo insieme un'applicazione di prova con un caso d'uso completo, disponibile su &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 ed extension: un approccio Swift puro</title>
    <link href="https://www.sofapps.it/it/blog/swift-stored-properties-extensions/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>Le extension di Swift non possono contenere stored properties, e la semplice computed property che restituisce sé stessa va in loop fino a saturare l'heap. Il post mostra una soluzione Swift pura che conserva i valori in un dizionario statico dietro una computed property, al posto degli associated object del runtime Objective-C. Due aggiornamenti risolvono il valore condiviso tra istanze indicizzando il dizionario per istanza, prima con debugDescription e poi con l'indirizzo di memoria.</summary>
    <content type="html">&lt;p&gt;Una delle domande più frequenti sulle extension di Swift riguarda le stored properties. Quante volte avete desiderato una stored property nella vostra ultima, fantastica extension, per parametrizzare qualche comportamento?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Come forse sapete, Swift non permette le stored properties nelle extension. È una scelta di design: &amp;quot;Extensions may not contain stored properties.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;L'errore più comune è cercare di aggirare il limite con qualcosa del genere:&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;Copia&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;Anche se il codice compila senza errori, ci si accorge presto che è completamente sbagliato: il riferimento ciclico alla computed property fa girare il codice in loop finché l'heap non è saturo di chiamate quasi identiche.&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;Fumetto di un volto pensieroso con la mano sul mento&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;Il secondo approccio comune è cercare su Google. Si trovano alcuni trucchetti ingegnosi per aggiungere qualcosa che assomigli al concetto di stored property da usare dentro le extension (vedi i riferimenti).&lt;/p&gt;
&lt;p&gt;Uno dei workaround più (ab)usati si affida al runtime di Objective-C, con una soluzione basata sulle funzioni objc_getAssociatedObject e objc_setAssociatedObject.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Anche se queste soluzioni non hanno nulla di sbagliato, un approccio Swift puro sarebbe molto più elegante. È questo il motivo del post: provare a creare un'extension Swift pura con supporto alle stored properties.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;La soluzione proposta è molto semplice. Parte dall'assunto che le extension non accettano stored properties ma solo computed properties. Elaborando il concetto di struct, che sono tipi per valore, finiamo per aggirare il design delle extension aggiungendo di fatto il concetto di stored property. Il tutto in puro Swift.&lt;/p&gt;
&lt;p&gt;Un proof-of-concept vale più di mille parole. Ecco qui:&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;Copia&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;La struct Holder conterrà il valore privato che la nostra computed property espone al mondo, dando l'illusione del comportamento di una stored property.&lt;/p&gt;
&lt;h2 id=&quot;29-03-aggiornamento&quot;&gt;29/03: Aggiornamento&lt;/h2&gt;
&lt;p&gt;Come fatto notare da Paolo, anche se l'approccio funziona, andrebbe rivisto almeno in due punti per risolvere quanto segue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Visibilità private&lt;/strong&gt; per la struct Holder (al momento chiunque può accedere alle struct statiche di servizio e cambiarne il valore senza ulteriori controlli).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Istanze multiple&lt;/strong&gt; della classe estesa. L'approccio proposto soffre di un problema molto fastidioso: se si creano più istanze della classe estesa, ogni istanza condividerà lo stesso valore statico della struct Holder. Il problema dipende dalla natura della keyword static. Con un po' di fantasia possiamo essere creativi e risolvere la questione.&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;Fumetto a quattro vignette: qualcuno dice che l'immaginazione umana è infinita, gli viene chiesto di pensare a un nuovo colore e finisce sconvolto a un tavolo con bottiglie vuote&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;Quello che segue dovrebbe fare al caso nostro:&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;Copia&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;Qui abbiamo sfruttato una specie di hash table per conservare tutti i possibili valori che appartengono a istanze diverse della classe. Notate che self.debugDescription è un approccio davvero &amp;quot;grezzo&amp;quot;, e andrebbe elaborato un modo più conciso e intelligente per distinguere i riferimenti di istanze diverse. In ogni caso, come poc sembra funzionare.&lt;/p&gt;
&lt;h2 id=&quot;30-03-aggiornamento&quot;&gt;30/03: Aggiornamento&lt;/h2&gt;
&lt;p&gt;Non immaginavo che ci fosse un interesse così grande per questo argomento! Grazie a tutti. C'è ancora margine di miglioramento in questo approccio e, dopo una discussione molto cordiale con il mio amico Davide, ho deciso di dare un seguito all'articolo per includere alcuni dei suoi suggerimenti e migliorare l'hash table. Dato che usiamo una static var per emulare una hash table, non c'è più ragione di affidarsi alla struct. D'accordo. Questo farà risparmiare un bel po' di righe di codice. Vorrei anche migliorare il meccanismo della chiave della hash table usando l'indirizzo di memoria, come fanno i puntatori. La nuova versione dell'approccio è la seguente:&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;Copia&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, il meme di una faccia con un sorriso beffardo&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;Molto, molto meglio! C'è ancora un piccolo problema di &amp;quot;memory leak&amp;quot;, ma questa è un'altra storia.&lt;/p&gt;
&lt;p&gt;Happy swifty coding! 🖖🏻&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Creiamo un accessorio per HomeKit</title>
    <link href="https://www.sofapps.it/it/blog/homekit-accessory-arduino/" rel="alternate" type="text/html"/>
    <id>https://www.sofapps.it/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>L'articolo costruisce un gateway HomeKit con Homebridge su Raspberry Pi 3 e un hub basato su Arduino YUN che espone due endpoint HTTP. Un transistor NPN collegato a un telecomando RF 433Mhz apre un cancello automatico, mentre un sensore DHT22 fornisce temperatura e umidità. Una volta configurato il config.json di Homebridge e aggiunto il bridge nell'app Home, si controlla tutto con Siri.</summary>
    <content type="html">&lt;p&gt;Quest’articolo vuole essere una breve guida introduttiva su come creare un accessorio compatibile con HomeKit sfruttando componentistica di riuso ed open source. Alla fine dell’articolo, se avrete seguito correttamente tutti i passi, potrete giocare con un telecomando per il vostro cancello automatico di casa comandabile ed azionabile con Siri / HomeKit. Come bonus, avrete la possibilità di aggiungere un sensore ambientale di umidità/temperatura.&lt;/p&gt;
&lt;p&gt;Ingredienti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1x Raspberry PI3&lt;/li&gt;
&lt;li&gt;1x Arduino YUN (opzionale)&lt;/li&gt;
&lt;li&gt;1x Telecomando cancello automatico RF 433Mhz&lt;/li&gt;
&lt;li&gt;1x Transistor NPN&lt;/li&gt;
&lt;li&gt;1x Resistenza 2.2k&lt;/li&gt;
&lt;li&gt;1x Qualche cavo&lt;/li&gt;
&lt;li&gt;1x DHT22 (opzionale)&lt;/li&gt;
&lt;li&gt;5x Pazienza&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;HomeKit è il protocollo di Apple a cui gli sviluppatori ed aziende che creano hardware e dispositivi per la domotica devono aderire se intendono essere compatibili con l’assistente vocale Siri e l’applicazione Home installati di default su tutti i nuovi dispositivi iOS.&lt;/p&gt;
&lt;p&gt;HomeKit è un protocollo, ovvero una serie di regole e specifiche a cui i propri servizi devono aderire per potere essere integrati in maniera semplice e veloce con i dispositivi Apple. Il protocollo (nella versione developer no-profit) può essere scaricato e studiato liberamente a patto di accettare prima la licenza Apple annessa. Per maggiori informazioni è possibile andare qui:&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;Concettualmente, per potere creare qualcosa di funzionante (ed utile) con HomeKit è necessario creare due macro componenti che dialoghino tra di loro:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un bridge o gateway che parla con il protocollo HomeKit e converte tutti i nostri segnali input / output analogici e digitali in caratteristiche esposte al protocollo HAP.&lt;/li&gt;
&lt;li&gt;Una o più caratteristiche in grado di parlare con il server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tipicamente, le caratteristiche sono oggetti molto semplici ed elementari (lampadine, interruttori, sensori di temperatura, etc.). Per ragioni di costo e compattezza, dunque, risulta difficile potere implementare su di essi anche la logica di dialogo con il server.&lt;/p&gt;
&lt;p&gt;La soluzione più comune che viene adottata dalla maggior parte dei produttori è quella di creare un ulteriore indirezione — denominata HUB — che permette di “raccogliere” più dispositivi elementari sotto un unico raccoglitore che poi si occupa ed ha la capacità logica di parlare con il server; la serie smart living di IKEA e quella di Philips funzionano con questo principio. Ne consegue che le caratteristiche sono più leggere ed economiche al prezzo di un ulteriore oggetto da aggiungere alla catena che in verità non è una grossa complicazione o problema, considerando il fatto che riduce il costo complessivo degli oggetti finali, sensibilmente.&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;Schema di un gateway collegato a un hub, che a sua volta collega tre accessori, con l'area di copertura di ciascuno a sinistra&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;Fortunatamente, per quanto riguarda il gateway è già presente da tempo una implementazione open parecchio stabile e modulare, basata su node e che adotta ed implementa tutte le funzionalità e specifiche richieste per creare un Gateway di accessori per HomeKit richieste dal protocollo HAP.&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;Il funzionamento è molto semplice. Attraverso un file di configurazione si dichiarano gli accessori supportati dal gateway. Questi accessori altro non sono che dei plugin software, rappresentanti particolari caratteristiche esposte. Il file di configurazione è un semplice file JSON e gli accessori sono degli oggetti JSON appartenenti ad un array. Alcuni parametri dei singoli accessori sono obbligatori, altri sono opzionali e dipendono dalle singole implementazioni, essendo dei parametri di inizializzazione specifici.&lt;/p&gt;
&lt;h2 id=&quot;implementazione-gateway&quot;&gt;Implementazione — Gateway&lt;/h2&gt;
&lt;p&gt;Per prima cosa andremo a configurare il nostro gateway. Per questo compito ho deciso di usare un raspberry PI 3 su cui preventivamente avevo installato 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;Per installare homebridge, invece, vi basterà seguire le istruzioni riportate sulla pagina github del progetto. Io non ho riscontrato nessuna difficoltà.&lt;/p&gt;
&lt;p&gt;Una volta completata l’installazione saremo in grado di lanciare il nostro gateway con il comando homebridge. Al primo avvio, il server ci avviserà del fatto che non sono configurati degli accessori e, dunque, l’utilità del gateway è davvero limitata.&lt;/p&gt;
&lt;p&gt;Esiste una community molto attiva su npm ed, in pratica, si trova un plugin per quasi tutte le esigenze immaginabili. Nel nostro caso andremo a costruire un accessorio per aprire un cancello automatico, ossia per attuare un interruttore “stateless” di un telecomando RF. Aggiungeremo anche, se lo riteniamo opportuno, un sensore di umidità e temperatura che ci fornirà informazioni importanti (a costo praticamente zero) nella stanza in cui andremo a posizionare il nostro hub homekit.&lt;/p&gt;
&lt;p&gt;Prima di passare alla costruzione dei nostri sensori ed alla configurazione del nostro HUB è necessario completare la configurazione del nostro gateway, aggiungendo due moduli in grado di parlare correttamente con i sensori sopra descritti:&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;una volta installati, saranno disponibili da subito. ci basterà configurare opportunamente il file config.json di homebridge.&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;Copia&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;Al di la dei parametri banali quali nome e stanza, ogni modulo si aspetta di parlare con un indirizzo HTTP e ricevere determinate risposte per le operazioni richieste; ci basterà implementare questa logica semplice per completare il lavoro. Il gateway, infatti, si occuperà di tutto il resto per parlare correttamente con il protocollo Apple HAP.&lt;/p&gt;
&lt;h2 id=&quot;implementazione-hub-e-sensoristica&quot;&gt;Implementazione — HUB e sensoristica&lt;/h2&gt;
&lt;p&gt;Per costruire il nostro HUB che raggruppa e parla con i sensori, ho deciso di usare un vecchio arduino YUN che avevo comprato per un altro progetto e messo da parte in un cassetto. Tuttavia, se lo preferirete, potrete usare lo stesso raspberry che avete usato per costruire il gateway. Vi basterà riadattare i concetti di cui vi sto per parlare.&lt;/p&gt;
&lt;p&gt;Il nostro HUB dovrà implementare un server http che risponda agli endpoint specificati nel file di configurazione di homebridge sopra, restituendo i valori estratti dai nostri sensori collegati ai PIN di input/output del microcontrollore di Arduino.&lt;/p&gt;
&lt;p&gt;Prima di scrivere il codice per il nostro arduino, però, facciamo una pausa e dilettiamoci un pò di elettronica, costruendo quello che serve per trasformare un normale telecomando RF per cancelli automatici in un telecomando pilotato da Arduino.&lt;/p&gt;
&lt;p&gt;Per prima cosa dovremo individuare i pin del nostro pulsante di apertura e saldargli due spezzoni di filo.&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;Tre viste del circuito del telecomando: i pulsanti sul lato componenti e i punti di saldatura dei due fili sul retro&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;Nel frattempo avremo posizionato il nostro transitor N-P-N su una breadboard, opportunamente configurato con una resistenza da 2.2k sull’attuatore.&lt;/p&gt;
&lt;p&gt;La base del transistor andrà collegata al pin 7 di arduino. L’emettitore, invece, andrà ad uno dei cavi che abbiamo appena saldato sul telecomando. Il collettore verrà collegato ad uno dei capi del pulsante del telecomando ed alla massa di arduino.&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;Schema di montaggio con Arduino YUN, breadboard con transistor NPN e resistenza, e circuito del telecomando collegati da fili&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;In questo modo, avremo creato un circuito normalmente aperto che si chiude (premendo di fatto il pulsante del telecomando) solo quando arriva un impulso di una certa soglia inviato dal pin digitale. Ci resta da codificare queste informazioni in un linguaggio comprensibile per il nostro microcontrollore.&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;Foto del montaggio reale: Arduino YUN, breadboard con il transistor e scheda del telecomando uniti da fili colorati&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 è una piattaforma ibrida molto interessante basata su un server linux, un modulo wifi ed un microcontrollore AT (del tutto simile a quello usato su arduino uno). Il pregio di Arduino, rispetto altri concorrenti, è quello di essere assolutamente semplice ed efficace nella gestione degli input/output analogico/digitali, offrendo un linguaggio di programmazione basato su C di rapida comprensione. Per poter eccitare il nostro pin 7 di cui sopra, ci basteranno poche righe di codice:&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;Copia&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;a quanto sopra dobbiamo aggiungere la logica per il server HTTP. Arduino YUN include già una mini piattaforma HTTP server/client esposta in maniera molto semplice attraverso due oggetti di libreria denominati ClientBridge e ServerBridge. Il server bridge ci servirà per ascoltare le richieste provenienti dal mondo esterno ed il client per scrivere le nostre risposte a chi ci ha chiamato.&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;Copia&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;Resta da aggiungere il controllo di temperatura. Il sensore DHT22 è un sensore digitale ottimo per lo scopo: dal costo contenuto e dalla precisione digitale, non richiede taratura e può essere usato con una delle molte librerie per dispositivi a tecnologia DHT presenti.&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;il pin 1 è il pin di alimentazione&lt;/li&gt;
&lt;li&gt;il pin 2 è il pin dove vengono modulati e serializzati i dati&lt;/li&gt;
&lt;li&gt;il pin 3 è inusato&lt;/li&gt;
&lt;li&gt;il pin 4 è la massa.&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;Schema del sensore DHT22 su una breadboard collegato a una scheda Arduino per alimentazione, massa e dati&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;collegheremo il pin 2 al pin 4 del nostro arduino yun.&lt;/p&gt;
&lt;p&gt;leggere la temperatura e l’umidità anche in questo caso è molto semplice:&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;Copia&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;conclusioni-wrap-it-up&quot;&gt;Conclusioni — wrap it up&lt;/h2&gt;
&lt;p&gt;Bene. E’ il momento di mettere insieme tutti i pezzi. Una volta avviato lo sketch sul nostro Arduino, verifichiamo che tutti i comandi funzionino correttamente:&lt;/p&gt;
&lt;p&gt;/temp&lt;/p&gt;
&lt;p&gt;/switchOn&lt;/p&gt;
&lt;p&gt;A questo punto ci basterà avviare homebridge e configurare opportunamente la nostra applicazione Home inserendo il qrcode che appare a schermo e seguendo i passi illustrati dall’app Home di Apple. Alla fine avremo qualcosa di questo tipo a schermo:&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;L'app Home su iPad con scene e accessori preferiti, tra cui il cancello, il termostato del corridoio e il sensore del soggiorno&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;e la possibilità di parlare con il nostro amato dispositivo chiedendogli:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Che temperatura c’è a casa?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;oppure ancora:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Apri il cancello&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;considerazioni-finali&quot;&gt;Considerazioni finali&lt;/h2&gt;
&lt;p&gt;homebridge è una piattaforma open molto flessibile che permette di dialogare con il protocollo HAP di Apple in maniera rapida ed efficace attraverso mini moduli e semplici tecnologie basate su http.&lt;/p&gt;
</content>
  </entry>
</feed>
