<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andy Lawler</title>
    <description>The latest articles on DEV Community by Andy Lawler (@andylawler).</description>
    <link>https://dev.to/andylawler</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F157221%2Fb7eeff24-c665-496a-b258-cf4b7d58b92f.png</url>
      <title>DEV Community: Andy Lawler</title>
      <link>https://dev.to/andylawler</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andylawler"/>
    <language>en</language>
    <item>
      <title>Building Second Skin in public #2: empty states and the first photos 📸</title>
      <dc:creator>Andy Lawler</dc:creator>
      <pubDate>Sat, 07 Nov 2026 20:20:11 +0000</pubDate>
      <link>https://dev.to/andylawler/building-second-skin-in-public-2-empty-states-and-the-first-photos-1jco</link>
      <guid>https://dev.to/andylawler/building-second-skin-in-public-2-empty-states-and-the-first-photos-1jco</guid>
      <description>&lt;p&gt;Gooood evening 👋. If you read one of my &lt;a href="https://andrewlawler.github.io/posts/building-second-skin/" rel="noopener noreferrer"&gt;last posts&lt;/a&gt;, you'll know I'm building &lt;strong&gt;Second Skin&lt;/strong&gt;, an app for keeping track of your tattoos, and that I promised the odd update along the way. Well, here's the next one.&lt;/p&gt;

&lt;p&gt;At the end of that post I said the Collection tab was next. That's... sort of what happened. I took a little detour first, and then made some pretty good progress on getting the base layers in for the other tabs. Let me show you where I'm at.&lt;/p&gt;

&lt;h2&gt;
  
  
  📍 Where it's at
&lt;/h2&gt;

&lt;p&gt;Last time there were 18 merged pull requests, now there are 26. It might not sound like much but it's some pretty nice progress. Since the last update I've:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moved the shared bits (icon rows, the primary button and the empty state) into the design system.&lt;/li&gt;
&lt;li&gt;Built an empty state for Ideas, Bookings and Stats, so every tab now has one.&lt;/li&gt;
&lt;li&gt;Added a photo importer.&lt;/li&gt;
&lt;li&gt;Started the Add a piece sheet, with photos going in and out of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🧱 A detour into the design system
&lt;/h2&gt;

&lt;p&gt;Before I touched the Collection grid I wanted the shared pieces in place. Welcome, About you and Collection had all ended up with their own version of the same row (icon on the left, title and a line of text, pretty standard stuff), and they'd slowly drifted apart: some icons were 36pt and some were 40pt, some were centred and some sat at the top. Not a massive problem, but a drift nonetheless.&lt;/p&gt;

&lt;p&gt;One thing about personal projects is that you always start with your best intentions at heart but then you end up with code that has a lot of duplication just due to how you are working. At least for me, my personal projects are an escape from the rigidity of working on large scale apps, but that doesn't mean we should let our codebases get into disarray. Especially with AI now I didn't want to keep hacking away at different things and end up with something that was honestly going to be a nightmare to sort out. So I opted to stop and just get the fundamentals down first.&lt;/p&gt;

&lt;p&gt;Taking you back to the example I mentioned earlier. This row I had became the &lt;code&gt;IconRow&lt;/code&gt; which will be useful on a multitude of screens throughout the app. While I was at it I also shifted over the main button I'd used in the app to be the &lt;code&gt;PrimaryButton&lt;/code&gt; and then the &lt;code&gt;EmptyState&lt;/code&gt; followed so it could be re-used on the other pages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwwglpu9qo1yrvjsgu42f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwwglpu9qo1yrvjsgu42f.jpg" alt="Two IconRow examples on a white card: a plain row with a grid icon, &amp;quot;Keep every piece&amp;quot; and &amp;quot;Photos, placement, artist and story.&amp;quot;, and a tappable row with a pink heart icon, &amp;quot;Just got tattooed?&amp;quot;, &amp;quot;Log it and set up your aftercare&amp;quot; and a chevron" width="799" height="344"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;One &lt;code&gt;IconRow&lt;/code&gt;, plain and tappable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Having the help of Claude here was pretty handy as I managed to do the main bulk of the shifting and sculpting and then Claude helped me with getting some snapshot testing and documentation in place so when I do code reviews it can prompt me if I've forgotten to reuse something that I'd made earlier.&lt;/p&gt;

&lt;p&gt;One thing I picked up while moving the button over was that I'd made its label a plain &lt;code&gt;String&lt;/code&gt;, which means it would never get translated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; &lt;code&gt;Text(someString)&lt;/code&gt; with a &lt;code&gt;String&lt;/code&gt; shows the text as it is and never looks it up for translation. If you're building a reusable component, take a &lt;code&gt;LocalizedStringKey&lt;/code&gt; for the label instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I set a rule when I was doing the initial project discovery that I'd aim to shift something into the design system when it needed to be used in more than one place. You may now be thinking, "but Andy, you only had one empty state so far, so why did you move it now?" You are right, but honestly I opted to make the empty states consistent and I just thought it was easier to shift it all now.&lt;/p&gt;

&lt;h2&gt;
  
  
  🫙 An empty state for every tab
&lt;/h2&gt;

&lt;p&gt;When you first open Second Skin, every tab is empty, so the empty states are really the first thing anyone sees other than the onboarding. They all follow the same pattern: a faint grey preview of what the tab will look like, a title, one line explaining it, a black button and sometimes a pink link underneath. This may change, but honestly this is what I have now and I'm fairly happy with it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdy5rlkh7a3olpul8r5i3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdy5rlkh7a3olpul8r5i3.jpg" alt="The empty states for the Ideas, Bookings and Stats tabs side by side. Ideas shows a faint mosaic and &amp;quot;Start an idea&amp;quot; with a New idea button, Bookings shows two faint booking rows and &amp;quot;No bookings yet&amp;quot; with a New session button, and Stats shows a faint bar chart, &amp;quot;Stats build up as you go&amp;quot;, a New session button and a pink link &amp;quot;Or maybe add a piece you already have?&amp;quot;" width="799" height="545"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Ideas, Bookings and Stats, before you've added anything.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A few of them changed a bit from the designs once I actually built them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ideas&lt;/strong&gt; lost its "Suggest ideas for me" link. Suggestions are going to use Apple's on-device model, and that's planned for v2, so it didn't make sense to show a link to something that doesn't exist yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bookings&lt;/strong&gt; originally promised "a reminder the day before". Reminders aren't built yet, you'll be able to turn them off and I haven't decided on the timing either, so now it just says you'll get a reminder if you want one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stats&lt;/strong&gt; swapped "Log a sitting" for a link to add a piece you already have. A new session only counts towards your stats once you've logged how it went, so adding a piece you already have is the quicker way to see something there.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Large text broke everything (a little)
&lt;/h3&gt;

&lt;p&gt;Every screen gets snapshot tests at the biggest accessibility text size, and the empty state didn't hold up very well initially. The title went left aligned when it wrapped, the message was squashed into a narrow column and the "Add a piece" button wrapped onto two lines inside its capsule. The pictures also had fixed sizes, so they stayed tiny while the text around them got huge.&lt;/p&gt;

&lt;p&gt;Now the title stays centred, the button fills the width at those sizes and the pictures scale with the text using &lt;code&gt;@ScaledMetric&lt;/code&gt;. Every picture shares one little property wrapper for that, &lt;code&gt;PictureScale&lt;/code&gt;, so I'm not copying the maths into each screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwfuty95ga8tbckvjuo2q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwfuty95ga8tbckvjuo2q.jpg" alt="The Collection empty state at the largest accessibility text size, before and after the fix. Before, the camera picture is small, the message is squashed into a narrow column and the Add a piece button is pushed off the bottom. After, the picture is bigger, the message is wider and the full width Add a piece button fits on one line" width="800" height="780"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Collection at the biggest text size, before and after.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; If you use &lt;a href="https://github.com/pointfreeco/swift-snapshot-testing" rel="noopener noreferrer"&gt;SnapshotTesting&lt;/a&gt;, adding &lt;code&gt;TEST_RUNNER_SNAPSHOT_TESTING_RECORD=failed&lt;/code&gt; to your &lt;code&gt;xcodebuild&lt;/code&gt; command re-records only the snapshots that failed, without changing your scheme. It's really handy when you've made a change on purpose.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  📸 The first photos go in
&lt;/h2&gt;

&lt;p&gt;Then onto the bit I said I'd do last time, adding a piece. I split it into two parts, so I'll do the same with the write up. First was the photo importer and then the sheet itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  The photo importer
&lt;/h3&gt;

&lt;p&gt;This is the part that takes a photo you've picked and gets it ready to save. Claude wrote this one while I worked on the sheet as to be honest, I was quite happy to offload the image handling.&lt;/p&gt;

&lt;p&gt;When a photo comes in, it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gets downsized to a 2048px HEIC, plus a 400px thumbnail for the grids.&lt;/li&gt;
&lt;li&gt;Has all of its metadata stripped, including location. The app is private by design, so I don't want where you got tattooed syncing around with your photos.&lt;/li&gt;
&lt;li&gt;Gets a suggested colour for the piece's little colour dot, picked from the photo. Black and grey work doesn't get a colour at all, on any skin tone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It all runs off the main actor, so the app doesn't hang while it's working through a big batch of pictures.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Add a piece sheet
&lt;/h3&gt;

&lt;p&gt;This was the part I was looking at most, as I think the usability of this screen will make or break the app for a lot of people. The idea is that the top is a photo picker, once you pick images you get one nice cover photo which will be used for the piece once it's in the app, you can then add more pictures which show in a smaller carousel under the main cover. The picker section also has re-ordering, so you can choose to shift something else to be your cover photo if you find a better image of your piece later down the line.&lt;/p&gt;

&lt;p&gt;This sheet's been quite tricky and honestly just image handling and uploading took quite a chunk of my time, so I'm still actively working on the other aspects of the page, but I look forward to sharing more of it with you next time.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Things I learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.task(id:)&lt;/code&gt; restarts when its id changes.&lt;/strong&gt; I was clearing the picker selection inside the task, which changed the id and cancelled the import halfway through. &lt;code&gt;.onChange&lt;/code&gt; with a &lt;code&gt;Task&lt;/code&gt; fixed it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With &lt;code&gt;NonisolatedNonsendingByDefault&lt;/code&gt; on, a plain &lt;code&gt;async&lt;/code&gt; function runs on the caller's actor.&lt;/strong&gt; If you want it off the main actor, mark it &lt;code&gt;@concurrent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@Observable&lt;/code&gt; needs &lt;code&gt;@ObservationIgnored&lt;/code&gt; on every property wrapper,&lt;/strong&gt; especially important when using Swift Dependencies like I am.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shapes fill whatever space they're offered.&lt;/strong&gt; A &lt;code&gt;RoundedRectangle&lt;/code&gt; with only a width will happily grow to the full height, which made for some very tall "lines of text" in the Bookings picture. 😅

&lt;ul&gt;
&lt;li&gt;This app is one of the first apps I've truly tried to build for iPhone, iPhone Duo and iPad, and also support localisation, accessibility, basically everything. So I've been learning a lot about the structure of my views and how to best handle things like widths and heights.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔜 What's next?
&lt;/h2&gt;

&lt;p&gt;Next up is finishing the photo carousel: a message for when a photo can't be added, and a limit on how many you can add in total. Then the rest of the sheet, name and placement, style, colour, the optional history section and finally saving.&lt;/p&gt;

&lt;p&gt;There are a few decisions to make before I get there, like how you describe placement (an area plus front or back, or left and right as well?), what colour a black and grey piece gets, and what the minimum is before you can save.&lt;/p&gt;

&lt;p&gt;If you've got tattoos, I'd love to know how you'd describe where one is, is "left forearm, inside" enough or would you want something more specific? Let me know in the comments. 👇🏻&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>ios</category>
      <category>mobile</category>
      <category>showdev</category>
    </item>
    <item>
      <title>My blog is moving home: rebuilding my site in Swift with Ignite 🏡</title>
      <dc:creator>Andy Lawler</dc:creator>
      <pubDate>Tue, 03 Nov 2026 19:54:07 +0000</pubDate>
      <link>https://dev.to/andylawler/my-blog-is-moving-home-rebuilding-my-site-in-swift-with-ignite-3j7i</link>
      <guid>https://dev.to/andylawler/my-blog-is-moving-home-rebuilding-my-site-in-swift-with-ignite-3j7i</guid>
      <description>&lt;p&gt;Hi! 👋🏻 If you've read my last few posts, you might not know that they all have a second home now... my own site, &lt;a href="https://andrewlawler.github.io/" rel="noopener noreferrer"&gt;andrewlawler.github.io&lt;/a&gt;. This post is all about how it got there and why I rebuilt it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwtkob0siuqk8xdivnfkk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwtkob0siuqk8xdivnfkk.jpg" alt="The home page of andrewlawler.github.io: a round photo of Andy, &amp;quot;Hi, I'm Andy 👋🏻&amp;quot; with a short intro, three Get to know me cards (More about me, My apps, All posts) and the start of Latest posts" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🕰️ A site I forgot I had
&lt;/h2&gt;

&lt;p&gt;Back in October 2023 I built myself a little personal site using John Sundell's &lt;a href="https://github.com/JohnSundell/Publish" rel="noopener noreferrer"&gt;Publish&lt;/a&gt;, a static site generator written in Swift. This was back before the days of AI so it was definitely a scrappy project and it was honestly fun to see what could be made using Swift. The site itself was pretty barebones, I had one basic post which just outlined a few things about the site but that was it. I then didn't really write anything or touch the site... until now.&lt;/p&gt;

&lt;p&gt;When I began writing again, my first thought was to use the site but honestly it just wasn't really in the state to be used, so instead of waiting I opted to use my old &lt;a href="https://dev.to/andylawler"&gt;dev.to&lt;/a&gt; account instead. After a few posts on there, I thought it would be nice to try and get everything onto my own site, plus I had been thinking that I would need somewhere to hold my portfolio and the relevant support pages for Second Skin when it launches so it felt like the best time.&lt;/p&gt;

&lt;p&gt;When I came back to the repo, the first thing I did was try and build it again. The good news was it still built on the latest Swift. The bad news was that generating the site failed, because of a file rename I'd clearly started in 2023 and never finished, which is pretty typical of me to be fair. Once I got rid of the changes I'd made the site generated which was a success..... but it still had all the issues that drove me away in 2023 in the first place.&lt;/p&gt;

&lt;p&gt;The bigger problem though was Publish itself. Its last release was 0.9.0 back in April 2022, so it's pretty much unmaintained now. I didn't really want to start again on my site, using a library that in reality was never going to get any more updates. So I felt that before I even touched anything, I should consider how I'd even want my site to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔥 So why Ignite?
&lt;/h2&gt;

&lt;p&gt;So, if not Publish, then what? Well I had two real options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://astro.build" rel="noopener noreferrer"&gt;Astro&lt;/a&gt; or something similar.&lt;/strong&gt; Probably the lower maintenance choice, tons of themes and a big community behind it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/Ignite-Swift/Ignite" rel="noopener noreferrer"&gt;Ignite&lt;/a&gt;.&lt;/strong&gt; A static site generator from Paul Hudson, also in Swift, but you build your pages with a SwiftUI style syntax.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, Ignite was the clear winner for me. I'm passionate about Swift and honestly just building things with Swift has always been the goal for me so keeping this website powered by Swift was a priority. When I saw Ignite and how maintained it was, it was really a no brainer.&lt;/p&gt;

&lt;p&gt;If you've written any SwiftUI, Ignite will feel quite familiar. Here's a small part of my home page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;StaticPage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Home"&lt;/span&gt;

    &lt;span class="kd"&gt;@Environment&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;articles&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;HTML&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"Hi, I'm Andy "&lt;/span&gt;
                &lt;span class="kt"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"👋🏻"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"wave"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I'm an iOS engineer, currently working at Depop and based in Liverpool."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hero"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pages are structs, they have a &lt;code&gt;body&lt;/code&gt;, and you style things with modifiers. The whole site is then described in one &lt;code&gt;Site&lt;/code&gt; struct, which lists the pages, the layout, the themes and the RSS feed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;AndyLawlerSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Andy Lawler"&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;static&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://andrewlawler.github.io"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;homePage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MainLayout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;staticPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;any&lt;/span&gt; &lt;span class="kt"&gt;StaticPage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kt"&gt;About&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kt"&gt;Apps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kt"&gt;SecondSkin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;articlePages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;any&lt;/span&gt; &lt;span class="kt"&gt;ArticlePage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;PostLayout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Tip:&lt;/strong&gt; Ignite is still pre-1.0, so minor releases can break things. I've pinned it to an exact version (&lt;code&gt;exact: "0.7.2"&lt;/code&gt;) in &lt;code&gt;Package.swift&lt;/code&gt; and I'll update it on purpose rather than by accident.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🚀 One repo, deployed for free
&lt;/h2&gt;

&lt;p&gt;The old site had its source in one private repo and the built output in another. I think this was the advice at the time? Honestly, I can't quite remember. This time though, everything is all just in one public repo and a GitHub Actions workflow builds the site on each merge and releases it to GitHub Pages. Making the repo public is what keeps this free. A private repo deploying to Pages needs GitHub Pro, and honestly there's nothing secret in a personal blog anyway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;macos-26&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build site&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swift run AndyLawlerSite&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload site&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name != 'pull_request'&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-pages-artifact@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The build has to run on macOS, as that's where Ignite is developed and tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  🪜 The bits that tripped me up
&lt;/h2&gt;

&lt;p&gt;It wasn't all smooth sailing, so here are a few things that tripped me up and might save you some time if you try this yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Posts need to live in a subfolder.&lt;/strong&gt; Ignite puts every Markdown file in &lt;code&gt;Content/&lt;/code&gt; into your RSS feed and tag pages, and a Markdown file sat at the top level of &lt;code&gt;Content/&lt;/code&gt; actually crashed the build for me. So posts live in &lt;code&gt;Content/posts/&lt;/code&gt;, and normal pages like my privacy and support pages are Swift &lt;code&gt;StaticPage&lt;/code&gt;s instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch your Swift version on CI.&lt;/strong&gt; GitHub's stable &lt;code&gt;macos-26&lt;/code&gt; runner has Xcode 26 with Swift 6.2, but a newer swift-collections (one of Ignite's dependencies) needs Swift 6.4. Builds were fine on my Mac and failed on CI, so for now I've capped swift-collections in &lt;code&gt;Package.swift&lt;/code&gt; until the runner catches up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dates and quotes in front matter.&lt;/strong&gt; Ignite keeps the quotes around front matter values and only reads dates in a &lt;code&gt;y-M-d&lt;/code&gt; format, which caught me out when bringing posts across.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't keep the repo in iCloud.&lt;/strong&gt; My repo lived in my &lt;code&gt;~/Documents&lt;/code&gt;, which iCloud syncs. That gave me a weird codesign "detritus" error (&lt;code&gt;swift package reset&lt;/code&gt; sorted it) and a pile of duplicate "Site 2.swift" files that broke the build. 🤦‍♂️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignite's CSS wins by default.&lt;/strong&gt; Ignite sets link colours and button backgrounds directly, so if you want your own styles to stick, your overrides need to be just as specific.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ✨ What's on the site
&lt;/h2&gt;

&lt;p&gt;Now it's built out a bit more, here's what you'll find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Posts.&lt;/strong&gt; Everything I've written, with search and tag filters, going all the way back to my two posts from 2020.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;About.&lt;/strong&gt; A little more about me, what I'm passionate about and where I've worked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apps.&lt;/strong&gt; The apps I've worked on at Jigsaw, Sky Bet and Depop, plus my own ones like Second Skin and some older side projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RSS.&lt;/strong&gt; If you're still an RSS person (I see you 👀), there's a feed too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkeq7m31ngsoqgj35odn0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkeq7m31ngsoqgj35odn0.jpg" alt="The Posts page: a search box, tag filter pills from #ios to #techtalks, and post cards for Second Skin, the AI novice post and SwiftLeeds 2026" width="800" height="750"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6l6zdf1q8utdtbfjtlfl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6l6zdf1q8utdtbfjtlfl.jpg" alt="The About page on the How I got here tab: a timeline starting with a Computer Science degree in 2018, then Apposing, classi and Jigsaw" width="800" height="675"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also gave it a bit of a fresh coat of paint, with the iOS system pink as the accent colour and a little bit of motion as you scroll.&lt;/p&gt;

&lt;h2&gt;
  
  
  📍 So where will my posts live now?
&lt;/h2&gt;

&lt;p&gt;My site is now the home for everything I write. I write the posts in Obsidian, and a little script copies anything marked as published (plus its images) over into the site, so there's only ever one copy of each post to look after.&lt;/p&gt;

&lt;p&gt;I'm still going to post on dev.to too, as that's where a lot of you are reading this. Each post there has a &lt;code&gt;canonical_url&lt;/code&gt; pointing back to the copy on my site, so search engines know where the original lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔜 What's next?
&lt;/h2&gt;

&lt;p&gt;I always feel wary when I consider what's next with personal websites, I could say I have grand plans and then disappear again. However, I think this time I'll be here for a while. Keep an eye on the site for any upcoming posts and maybe some new designs when I think we need a fresh lick of paint. I'll also hopefully get myself a nice little domain name so I can drop the default GitHub Pages domain but we will see how that goes.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Building Second Skin in public: an app for your tattoos 🌹</title>
      <dc:creator>Andy Lawler</dc:creator>
      <pubDate>Sat, 31 Oct 2026 20:03:33 +0000</pubDate>
      <link>https://dev.to/andylawler/building-second-skin-in-public-an-app-for-your-tattoos-35lp</link>
      <guid>https://dev.to/andylawler/building-second-skin-in-public-an-app-for-your-tattoos-35lp</guid>
      <description>&lt;p&gt;Hi! 👋🏻 If you've read either of my last two posts, you've probably seen me mention &lt;strong&gt;Second Skin&lt;/strong&gt; and then quickly move on to something else... well, this time it finally gets a post all to itself.&lt;/p&gt;

&lt;p&gt;I've decided I'm going to build it in public. So every once in a while i'll do a little write up to say how far i've gotten, which bits I got wrong along the way and what are some things i've learned. This first one is really just an introduction which also aims to show you what i've done so far 🚀.&lt;/p&gt;

&lt;h2&gt;
  
  
  🌹 So, what is Second Skin?
&lt;/h2&gt;

&lt;p&gt;Second Skin is an iOS app for keeping track of your tattoos. The tagline is &lt;em&gt;"Your tattoos, from idea to healed."&lt;/em&gt; and the app is split into four tabs that pretty much follow that journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Collection.&lt;/strong&gt; The pieces you already have, either as a photo grid or dotted around a body map.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideas.&lt;/strong&gt; Moodboards for the tattoos you're thinking about, with references saved from Instagram, Pinterest, Safari or your own photos. Also the aim in the future here is to include foundation models to let the app suggest ideas to you based on the things you've got previously, got saved etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bookings.&lt;/strong&gt; Your upcoming sessions, and then a quick "How did it go?" once they've happened, so things like time in the chair, cost and a pain score out of 10 are scored.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stats.&lt;/strong&gt; Hours in the chair, how much of your skin is covered, your go-to artist, your most painful session and a few more. This should hopefully just be a fun way to keep track and should help when you get the dreaded &lt;code&gt;How many have you got?&lt;/code&gt; question.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running through all of it is aftercare. When you finish a session you can start an aftercare routine (usually the one your artist gave you) and the app will remind you of each step every day until it's healed. This is mainly just to help remind you as the app in no way will be giving medical information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsquaeqa43otee4lyoodt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsquaeqa43otee4lyoodt.jpg" alt="The Second Skin Welcome screen: a fan of three tattoo photos, the title &amp;quot;Second Skin&amp;quot;, the tagline &amp;quot;Your tattoos, from idea to healed.&amp;quot;, three features (Keep every piece, Plan what's next, Look after it) and a Get started button" width="800" height="857"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Welcome screen, with three of my own pieces. 🌹&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🖋️ Why build it?
&lt;/h2&gt;

&lt;p&gt;I'm a bit of a tattoo enthusiast myself, I started really just appreciating tattooing for what it is. I think that all started for me as I've always been into Hardcore &amp;amp; Metal music and tattooing is quite prominent in those scenes. This led to me being interested in traditional tattooing and then has led to me having quite a lot of tattoos myself. Every piece you see in-app as promotion will likely just be one of my own tattos.&lt;/p&gt;

&lt;p&gt;Over the years getting tattoo'd i found that it was often hard to keep track of appointments, usually had to just add the booking into my own calendar and hope i'd remember. I then had to remember days before the session to do things like buy aftercare, buy food etc and prep for the session. I then had a bit of a hard time collating ideas I wanted to get in the longer term and also keeping track of pictures of the pieces I had. All of this led to me wishing there was something simple and beautiful in place to do all of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏷️ Why "Second Skin"?
&lt;/h2&gt;

&lt;p&gt;"Second skin" is actually the name for the protective film that goes over a fresh tattoo. I liked that the name also is resonant with tattoos being your second skin and since the app is about collection of your tattoos it makes sense that the app really is your second skin.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔒 Private by design
&lt;/h2&gt;

&lt;p&gt;Tattoos can be pretty personal, so this was one of the first things I decided on: no sign-up, no ads, no tracking and no servers.&lt;/p&gt;

&lt;p&gt;Everything lives on your devices and syncs through your own iCloud account using CloudKit's private database. There are no Second Skin servers for your data to end up on, which also means I never see any of it. If you're signed out of iCloud it all just stays on your device. The aim is for the App Store privacy label to say "Data Not Collected", and for that to actually be true. I also think this is incredibly important as for a lot of us, our tattoos really are a thing we've done for ourselves, so I think storing this type of information should be the same.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnro3houcn44t8rb8jf5u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnro3houcn44t8rb8jf5u.jpg" alt="The three privacy promises from the About you screen: Private to you (your details and collection live on your devices and in your own iCloud), We never see it (there are no Second Skin servers, nothing is sent to us) and No account, no tracking (no sign-up, no ads, no analytics on your photos" width="799" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The privacy promises you see when you first set up the app.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎨 The design
&lt;/h2&gt;

&lt;p&gt;Before writing any code I sat down and tried to be inspired by some of my favourite apps. I used the help of AI to just collate a mood board of all different designs the apps I really love have used. This then let me mock up a few different ideas for how Second Skin will look. In the end the clean native look won for me. I think if the app is going to hold lot's of your tattoos, lot's of information and potentially lot's of colourful things, I would prefer that the app itself is quite clean and stripped back so you can see exactly what you are looking for. Thefore....&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Photos lead.&lt;/strong&gt; Your tattoos are the hero, so the app is built around big rounded photo cards and grids.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Liquid Glass for controls only.&lt;/strong&gt; The tab bar, toolbar buttons and floating controls get glass, and anything sitting on top of a photo gets a plain frosted material instead, as the HIG suggests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colour in small doses.&lt;/strong&gt; The surfaces are neutral, with one rose accent (&lt;code&gt;#D9485F&lt;/code&gt;) for primary actions and whatever's coming up next.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard iOS type sizes only.&lt;/strong&gt; No custom font sizes, so Dynamic Type just works.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🧱 The tech
&lt;/h2&gt;

&lt;p&gt;For anyone curious, here's what it's being built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SwiftUI&lt;/strong&gt;, targeting &lt;strong&gt;iOS 27&lt;/strong&gt; with Liquid Glass, running on iPhone, iPhone Duo and iPad from v1. Supporting the bigger screens from the start keeps my layouts honest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/pointfreeco/sqlite-data" rel="noopener noreferrer"&gt;SQLiteData&lt;/a&gt;&lt;/strong&gt; from Point-Free for the database and CloudKit sync, instead of SwiftData.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/pointfreeco/swift-dependencies" rel="noopener noreferrer"&gt;Swift Dependencies&lt;/a&gt;&lt;/strong&gt; for swapping in fakes for things like the clock, notifications and photos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/pointfreeco/swift-snapshot-testing" rel="noopener noreferrer"&gt;SnapshotTesting&lt;/a&gt;&lt;/strong&gt; for image tests of every screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SQLiteData was probably the biggest decision so far. SwiftData would have been the obvious pick, but SQLiteData gives me live queries that work inside my &lt;code&gt;@Observable&lt;/code&gt; screen models (not just in views), plain SQL for all the stats sums and counts, and CloudKit sharing. That last one means one day you could share an idea with your artist without me needing to run a backend. The trade-off is writing my migrations by hand in SQL, which to be fair has been a nice refresher.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; CloudKit only lets you &lt;em&gt;add&lt;/em&gt; to your schema once it's in production, you can't rename or delete fields. If you're syncing with CloudKit, it's worth spending a bit more time on your data model up front before anything ships.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🤝 How I'm building it
&lt;/h2&gt;

&lt;p&gt;In my last post I mentioned the one rule I set for this project: I write the code. Claude explains things, reviews my work and writes the parts I hand over to it, which is usually the repetitive stuff I don't learn much from. For example, I wrote the first few database tables myself to learn the pattern and then handed the rest over once I had it down.&lt;/p&gt;

&lt;p&gt;The rest of the process is pretty much how I'd want a team to work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A branch and pull request for every change.&lt;/strong&gt; With a template, no more than 15 files, then squash and merge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requirements before code.&lt;/strong&gt; Before I start a ticket, Claude writes up a list of requirements, kind of like a product manager would. This honestly just helps me stay on track when i'm building things.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decision records in the repo.&lt;/strong&gt; Things like "why iPad from v1" or "why the design system grows from screens" get written down in the same PR as the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A review before every PR.&lt;/strong&gt; Claude runs a code review on my changes before I raise them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A handoff at the end of every session.&lt;/strong&gt; A skill I wrote saves where I got to in Obsidian, so the next session can pick straight back up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's probably a lot of process for a side project, but it means I can put it down for a week and come back without wondering what on earth I was doing.&lt;/p&gt;

&lt;p&gt;It's also honestly my first time using AI in a side project. I think for me, using AI is helping because this is a side project. I'm working as an iOS Engineer for 8.5 hours during the day before I even sit down to work on this project. If i didn't at least try and lean into AI to help streamline the process I probably wouldn't reach the MVP stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  📍 Where it's at
&lt;/h2&gt;

&lt;p&gt;I started on 15 October and as of writing there are 18 merged pull requests. So far that's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The design, the architecture plan and a release plan for v1.&lt;/li&gt;
&lt;li&gt;The whole database schema, plus sample data built from photos of my own tattoos.&lt;/li&gt;
&lt;li&gt;The app shell, with all four tabs.&lt;/li&gt;
&lt;li&gt;Onboarding: a Welcome screen and an "About you" screen for your name, photo and currency. No account needed.&lt;/li&gt;
&lt;li&gt;A debug menu (shake the device in a debug build) to reset onboarding, wipe the data or load the sample data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff5yvk79t5chtccteetzq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff5yvk79t5chtccteetzq.jpg" alt="Three screens in dark mode: Welcome, About you filled in with the name Andrew, and the empty Collection tab asking you to add your first piece" width="799" height="545"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Where things are right now, in dark mode: Welcome, About you and an empty Collection.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;v1 is going to include all four tabs, aftercare, reminders and the share extension for saving ideas. Things like on-device AI suggestions for ideas, search and widgets will come later. There's also a little Easter egg planned for v1, but I'm going to keep that one quiet for now. 🤫&lt;/p&gt;

&lt;h2&gt;
  
  
  🔜 What's next?
&lt;/h2&gt;

&lt;p&gt;Next up is the Collection tab: the photo grid, adding a piece and the body map. That means building a proper photo pipeline, which should make for a good post of its own.&lt;/p&gt;

&lt;p&gt;Along the way I'm also planning to write about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choosing SQLiteData over SwiftData, and what it's like day to day&lt;/li&gt;
&lt;li&gt;Designing an app with AI as a sounding board (and the app icon saga)&lt;/li&gt;
&lt;li&gt;Building for iPhone, iPhone Duo and iPad from day one&lt;/li&gt;
&lt;li&gt;What it's like making a rule that &lt;em&gt;you&lt;/em&gt; write the code when AI could just do it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've got tattoos, I'd love to know how you keep track of yours right now and what you'd want from an app like this. And if there's a part of the build you'd like me to go deeper on, let me know in the comments. 👇🏻&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>ios</category>
      <category>mobile</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Once an AI novice, now maybe a little less of one ✨</title>
      <dc:creator>Andy Lawler</dc:creator>
      <pubDate>Mon, 26 Oct 2026 22:57:25 +0000</pubDate>
      <link>https://dev.to/andylawler/once-an-ai-novice-now-maybe-a-little-less-of-one-lpo</link>
      <guid>https://dev.to/andylawler/once-an-ai-novice-now-maybe-a-little-less-of-one-lpo</guid>
      <description>&lt;p&gt;Hi! 👋🏻 It's me again. If you read my last post, you'll know I've just come back to this blog after six years away. A lot has changed in that time, for me and for the landscape of iOS. One of the biggest changes for me has been AI and how I work with it.&lt;/p&gt;

&lt;p&gt;So this one is a bit more personal. It's about where I started with AI, the mistakes I made and what I've learned so far. If you're someone who takes pride in knowing your stuff, and AI feels a bit scary, this one's for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Knowledge was my superpower
&lt;/h2&gt;

&lt;p&gt;Before I joined Depop (my current role), my AI usage was pretty much asking ChatGPT a few basic questions when the Apple Documentation, developer forums, Stack Overflow or asking colleagues couldn't help me solve a problem.&lt;/p&gt;

&lt;p&gt;For me, knowledge was always my superpower. I wanted to know the syntax for things off by heart, I wanted to know the nuances of different APIs, when to build certain things and when not to. I wanted to be the person who people would look to ask when they needed help or the person that the product manager reached out to when they had an urgent issue. Before the world of AI this was the way I saw to try and push myself forward and this took a lot of outside learning and time.&lt;/p&gt;

&lt;p&gt;So when AI first started coming into the iOS landscape, I was like most people: very sceptical. Not only of how good it could be. If I'm honest, I kind of wanted it to not be that good. I took a lot of satisfaction in being the person who knew a lot of the little details about lots of different topics and it just so happened that AI would probably be a little bit better than me at that. It could probably answer all the questions people asked with more detail in less time. This concerned me. It left me asking myself: &lt;em&gt;if AI can do this better than me, what can I do better than AI?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🐣 Getting started
&lt;/h2&gt;

&lt;p&gt;About 14 months ago I joined Depop, and joined a team with a very different mindset than the one I was in before. This team embraced change, it embraced AI and was set out to utilise it as much as possible. Unlike my prior role, I suddenly had access to all the latest and greatest tools and I was surrounded by people who also had much more experience with them than me. &lt;/p&gt;

&lt;p&gt;I, on the other hand, was still writing all of my work by hand. I'd never used any of these tools before, and I didn't really know what they could do. To be fair, 14 months ago I don't think many of us knew either.&lt;/p&gt;

&lt;p&gt;In my previous role I was a Senior iOS Engineer in a team with lots of varying skill levels. Without AI, it was my job to help, mentor and be the person who solved the tough tasks when they needed solving. I'd completed huge migrations, worked on vast technical challenges and written tons and tons of documentation, and I'd never relied on AI or even thought &lt;em&gt;I wonder how this would have gone if AI did it&lt;/em&gt;. The thought of letting go of this and taking a step back to begin using AI was a little daunting to me.&lt;/p&gt;

&lt;p&gt;But the team I was joining was much more open minded and this really opened my eyes. My first step was just installing Claude and giving it a go. It felt like a similar experience to the first time I ever used Xcode, I didn't really know what to expect but the results honestly blew me away. I had no real setup, I didn't even know what a context window was, or a skill or anything for that matter but I was still producing work in a more efficient way than I was before. This was honestly quite exciting.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚡ So, where did I go from there?
&lt;/h3&gt;

&lt;p&gt;Well like everyone probably did, I might have gotten a bit carried away. Even before AI I was always probably known for moving quickly. Even at school my parents would be told by teachers that I just did things very quickly and maybe I needed to slow down. I remember in my first iOS role as a Junior I was told to not bring more than 3 pieces of work onto the board at once as I couldn't manage them all at the same time. So you can probably imagine what I attempted to do when I had AI to basically duplicate myself... I just tried to do too much. I think I found out quickly that you &lt;em&gt;can&lt;/em&gt; do it, but it doesn't mean you should. My work was good but it wasn't as high quality as my work before and arguably I hadn't learned as much from the work as I could have. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; I think a key thing someone told me early on is that if AI can do something you would have done before in 60% of the time, at least spend another 10% of the original time reviewing and analysing what you have done, you'll still have saved 30% and it will at least be something good. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwzaogkn6wzcgtf08jxat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwzaogkn6wzcgtf08jxat.png" alt="Bar chart: before AI, doing the work takes 100% of the time. With AI, the AI-assisted work takes 60%, reviewing and understanding it takes another 10%, and 30% is saved" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🌊 Information overload
&lt;/h3&gt;

&lt;p&gt;Once I had got accustomed to the basics of using Claude I wanted to try and progress a little more. Lucky for me I had people around me who were much further along in their AI journey than I was. We regularly had sessions in which people would share the skills they had been working on, the different use cases for AI they had found and basically everything else weird and wonderful about the AI landscape that maybe we would find interesting. Things like cookbooks, recipes, hooks all sorts.&lt;/p&gt;

&lt;p&gt;This was amazing, it was my first real look into what was possible but it was just.... a lot of information? I think the expectation was just that everyone would be on the ball with everything but the landscape changed so much that it almost felt hard to digest, at least for me. So my plan changed to just: &lt;em&gt;can I make one small change at a time?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🪜 One small step at a time
&lt;/h2&gt;

&lt;p&gt;So I took small steps. As with anything, I just needed to at least start.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F92fepmc2fhhd1pjhjwss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F92fepmc2fhhd1pjhjwss.png" alt="Four rising steps: 1. Use other people's skills, 2. Write your own skills, 3. Add hooks, 4. Build a knowledge base" width="799" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Using other people's skills.&lt;/strong&gt; I started by trying the skills others had built and presented, seeing how they worked and how I could best make use of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writing my own.&lt;/strong&gt; Once I was comfortable with that, I tried creating my own skills. Even to this day it's become a great way to share knowledge within the team and the organisation. Personally I've contributed by writing a few skills such as:

&lt;ol&gt;
&lt;li&gt;A skill to review your Claude usage to give you tips to improve (kind of like what this one small step at a time approach did for me).&lt;/li&gt;
&lt;li&gt;A skill to help you with end of year reviews, utilising Claude to pull feedback for people you work with.&lt;/li&gt;
&lt;li&gt;A skill to help write better documentation for a specific architecture we use.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks.&lt;/strong&gt; One problem I realised after having such a large amount of skills to use was just... how do I know when to use them? We know Claude is supposed to invoke them but that doesn't always happen. For me I had to set up hooks to let Claude tell me when I might want to use a certain skill. This has been really valuable for me and it's something I've shared with others within my team who had similar concerns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A knowledge base.&lt;/strong&gt; Most recently, I set up a knowledge base. My notes live in Obsidian, and &lt;a href="https://github.com/tobi/qmd" rel="noopener noreferrer"&gt;qmd&lt;/a&gt; indexes them so Claude Code can search them for context before asking me. This post actually started life there as a page of raw notes. For me this was probably a mistake I made for the longest time, I didn't realise how little useful context Claude actually had about me in its memory and making a change to actually formalise the storage has had a huge impact.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; A skill is a set of instructions that Claude loads when a task needs it. If you find yourself explaining the same thing to Claude more than once, that's a good sign it should be a skill.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I recently gave a small talk at our iOS guild, and my main suggestion was simply this: make one small improvement to your workflow at a time. With AI it can feel like you should be doing everything at once, but as I've found over the last 14 months, that doesn't really work and my approach has always just been to make one small step at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  📱 Putting it into practice: Second Skin
&lt;/h2&gt;

&lt;p&gt;In my last post I mentioned &lt;strong&gt;Second Skin&lt;/strong&gt;, my side project for keeping track of your tattoos. It's where I've been putting all of this into practice outside of work.&lt;/p&gt;

&lt;p&gt;I made one rule early on: I write the code. Claude explains things, reviews my work and only writes parts when I ask it to, which is usually the repetitive stuff I don't learn much from. &lt;/p&gt;

&lt;p&gt;Before I start a ticket, Claude writes up a list of requirements (Kind of like a product manager might do). Before I raise a pull request, it reviews my changes. At the end of each session, a handoff skill I wrote saves where I got to inside Obsidian, so the next session can pick straight back up.&lt;/p&gt;

&lt;p&gt;I've also used it as a sounding board for design, exploring different directions for the app and going through round after round of app icon ideas. I'll be writing more about building it soon. 👀&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Where I am now
&lt;/h2&gt;

&lt;p&gt;14 months on, I feel a lot more confident when it comes to AI and speaking about my experiences (which is what inspired this post). AI has become a core part of how I work, it can act as a sounding board for ideas, work as a partner when thinking about large technical problems or solutions, it can work as a planner helping me split things up and articulate them in ways to share with different stakeholders and much much more. Over time I've learned more and more use cases and honestly there's probably way more I haven't even realised yet.&lt;/p&gt;

&lt;p&gt;I'd say I'm still getting used to adapting my thinking about where I sit in the landscape now. I've definitely shifted from being focused on every piece of syntax and nuance and now I'm more focused on engineering solutions and following good software principles. I've found this is the best way to work with AI to get the best solutions but overall I've realised that AI isn't this scary thing, even for those of us who saw the knowledge we had before AI as our superpower.&lt;/p&gt;

&lt;p&gt;So, what can I do better than AI? I can be the guide: the person enforcing good architecture and software principles, and steering AI towards the best solutions. We should use AI to our advantage, and let it take the things that would take us the most time for the least benefit. That creates the space for the things AI can't do on its own, like thinking about the larger scale problems we have and how we can transform the areas we work in.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 If you're where I was
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Make one small improvement at a time.&lt;/strong&gt; You don't need to adopt everything at once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with what other people have built.&lt;/strong&gt; Try your team's skills and tools before writing your own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn the tools before speeding up.&lt;/strong&gt; Spend some time learning how they actually work before trying to do more, faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give the tools you have a go.&lt;/strong&gt; Whether they're personal tools or tools at work, AI gives us so many amazing ones. It's on us to try them and see what works for us.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🌱 Still a bit of a novice?
&lt;/h2&gt;

&lt;p&gt;I'm still maybe considered a novice, and I'm still getting used to this world of AI, but I'm proud of where I'm at now with it compared to last year. It definitely feels like I'm getting somewhere, and I want to keep exploring. If you're on the same journey, I'd love to hear how you're finding it, or the one small improvement that made the biggest difference for you, in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Back after 6 years: my SwiftLeeds 2026 best bits 🎤</title>
      <dc:creator>Andy Lawler</dc:creator>
      <pubDate>Sat, 17 Oct 2026 20:08:34 +0000</pubDate>
      <link>https://dev.to/andylawler/back-after-6-years-my-swiftleeds-2026-best-bits-2687</link>
      <guid>https://dev.to/andylawler/back-after-6-years-my-swiftleeds-2026-best-bits-2687</guid>
      <description>&lt;p&gt;Hi! 👋🏻 I'm Andy. It's been over 6 years now since I last wrote on this blog, it baffles me too that it's been that long... When I started writing here I was just a university student who had found iOS development and started doing tons and tons of YouTube tutorials and courses (shoutout to Sean Allen for those). Over time I felt like I learned something and I wanted to share it with others.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpsb64ca4luxd0be8xoju.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpsb64ca4luxd0be8xoju.png" alt="My profile picture" width="268" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📍 Where have I been?
&lt;/h2&gt;

&lt;p&gt;After a short while of learning iOS on my own, I wanted to at least see what the real world of work was like so I began spending my free-time at an app agency, this let me see how teams functioned and what a real working environment was like. Off the back of that, I managed to get a placement year during my degree working for Jigsaw which at the time was a dating app based in Manchester.&lt;/p&gt;

&lt;p&gt;This was my first real insight into what working on a real app was like. I managed to work on and ship my own features, test releases and really feel part of a team.&lt;/p&gt;

&lt;p&gt;After going back to university and finishing my degree, I then moved on to work for Sky Bet in Leeds. There I worked on the main Sky Bet iOS app each day, building things like the dynamic content system to show different things on the home screen to users and then later became quite a key part in a huge migration to a brand new Sky Bet app which saw us re-do 70% of the app.&lt;/p&gt;

&lt;p&gt;That was quite a challenge and I definitely wanted to try something new after that experience, so now I'm working at Depop as part of the Better Matching Experience team. Here I get to work daily on improving the experience for our users on the home, discover, search screens and much more. Enough about me anyway... why am I back?&lt;/p&gt;

&lt;p&gt;Well, I just attended the SwiftLeeds iOS conference for a whopping 6th time. Yes, you read that right, 6th time. It left me with the motivation to share and that's what has led me to revive this blog. So without further ado, here is a little round-up of the conference, my favourite bits and some takeaways.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo7uy9z4qfsr37jo0iodj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo7uy9z4qfsr37jo0iodj.jpg" alt="Boarding pass number six" width="800" height="1067"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Boarding pass number six. ✈️&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🏆 My two favourite talks
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Delightful Text-Driven Experiences with SwiftUI's TextRenderer (&lt;a href="https://eliperkins.com" rel="noopener noreferrer"&gt;Eli Perkins&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Eli works on &lt;a href="https://apps.apple.com/us/app/particle-personalized-news/id6683283775" rel="noopener noreferrer"&gt;Particle&lt;/a&gt; and showed how SwiftUI's &lt;a href="https://developer.apple.com/documentation/swiftui/textrenderer" rel="noopener noreferrer"&gt;&lt;code&gt;TextRenderer&lt;/code&gt;&lt;/a&gt; lets you bring your text to life and really delight your users. Eli's talk made me realise that we often think about animating our screens and creating interesting things for our users, but I don't often consider doing the same with the text as well.&lt;/p&gt;

&lt;p&gt;So how do text renderers work and how do we use one? Well first, to use them you can add the &lt;code&gt;.textRenderer&lt;/code&gt; modifier to your text, passing in a renderer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;textRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Passthrough&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create a renderer, you conform your struct to the &lt;code&gt;TextRenderer&lt;/code&gt; protocol and implement &lt;code&gt;draw(layout:in:)&lt;/code&gt;. The simplest one just draws every line as normal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Passthrough&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TextRenderer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;inout&lt;/span&gt; &lt;span class="kt"&gt;GraphicsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SwiftUI hands your renderer the text broken into lines, and each line into runs. A run is a chunk of the line that's styled differently from the text around it, so a bold word or an inline icon, for example, ends up in its own run. Inside each run are the glyphs: every letter, space and punctuation mark.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffxy73x29olsyvn8savx0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffxy73x29olsyvn8savx0.png" alt="How renderers work" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can apply operations like opacity and colour to any of those levels, and group them, much like you would with images. Every &lt;code&gt;TextRenderer&lt;/code&gt; is also &lt;code&gt;Animatable&lt;/code&gt;, so if you add an &lt;code&gt;animatableData&lt;/code&gt; property and animate it, you can reveal text line by line or glyph by glyph.&lt;/p&gt;

&lt;p&gt;Here's a quick example of that. This renderer fades each glyph in and slides it up into place, one after the other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;AppearRenderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TextRenderer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;animatableData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;inout&lt;/span&gt; &lt;span class="kt"&gt;GraphicsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Lines → runs → glyphs&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;glyphs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;glyphs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;glyph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;glyphs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enumerated&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;
            &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
            &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translateBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;glyph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Animate &lt;code&gt;progress&lt;/code&gt; from 0 to 1 and you get this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4d56hr68giz6huso3712.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4d56hr68giz6huso3712.gif" alt="Example renderer gif" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Paul Hudson's &lt;a href="https://github.com/twostraws/Prismic" rel="noopener noreferrer"&gt;Prismic&lt;/a&gt; is a collection of ready-made renderers to play with. I'm starting there while exploring ways to bring some text renderers to my personal projects and also at work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Building Beyond Mistakes (&lt;a href="https://github.com/FrankSolleveld" rel="noopener noreferrer"&gt;Frank Solleveld&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;My favourite talk on day two had no code in it. Frank wasn't even supposed to be doing a talk at the conference but as one of the other speakers fell ill, Frank was ready in the wings to give us his talk.&lt;/p&gt;

&lt;p&gt;This talk was different from the others. Frank talked about his start with iOS development, how he found the love for building things but as most of us did, he struggled when he had his first real taste of working in a company. I still remember myself the first time I worked on a real app as part of a company and how different that experience was compared to the apps I'd spent my own time building, so I could relate to this part of the talk.&lt;/p&gt;

&lt;p&gt;Frank took us on a journey, where he talked about his doubts and confidence knocks he had during the early start of his career but then how he managed to really excel and eventually find his way to where he is today. A few things from his talk that I'm taking with me:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faknazl4631qeol59mfv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faknazl4631qeol59mfv9.png" alt="Franks tips" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💬 People are just people, even conference speakers. Everyone is just part of the community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This talk really resonated with me, and I think it did for everyone else too, as after speaking to other attendees it seemed to be everyone's favourite of the conference. I'm looking forward to seeing this one published online.&lt;/p&gt;




&lt;p&gt;Some other talks I really enjoyed...&lt;/p&gt;

&lt;h2&gt;
  
  
  🤖 Working with AI without losing the craft
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Bringing back the love of Swift (&lt;a href="https://www.avanderlee.com" rel="noopener noreferrer"&gt;Antoine van der Lee&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Antoine opened the conference with this one. This talk hit the mark with everyone in the room, as I think we all ask ourselves quite often if the vast change to our careers due to AI has made us love the code we are writing less.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💬 Are we losing our love of Swift as we write less of the code ourselves?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Antoine raised the concern that developers aren't really taking as many courses anymore. People are even reading fewer articles which doesn't bode well for me beginning to write more on this blog. He also went on to say that developers are exploring code less, but in reality we are shipping more than ever. &lt;/p&gt;

&lt;p&gt;I can only speak from my own experience but I feel that. I've always been a relatively high-output engineer and I'm a fan of having a few things on the go, but AI has made that a different ball game.&lt;/p&gt;

&lt;p&gt;The sheer amount of code output I see per week now with AI does mean that we aren't as close to the code we are writing and I know for myself, I'm reading less and exploring less online as a result. This talk made me reflect, and I think the outcome for me is that I want to ground myself more in the technology I'm using every day.&lt;/p&gt;

&lt;p&gt;Alongside these topics, Antoine shared some tips for working with AI, such as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcw6fo0xz51lwi17zo9lh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcw6fo0xz51lwi17zo9lh.png" alt="Antoines tips" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;He also shared some handy tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.avanderlee.com/ai-development/agentic-ios-development-rocketsim-rockettrace/" rel="noopener noreferrer"&gt;RocketSim and RocketTrace&lt;/a&gt;, a CLI and agent skill for driving the simulator, plus Xcode Instruments for AI agents.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sosumi.ai" rel="noopener noreferrer"&gt;sosumi.ai&lt;/a&gt;, Apple's docs (including the Human Interface Guidelines) in a form agents can read.&lt;/li&gt;
&lt;li&gt;His post on &lt;a href="https://www.avanderlee.com/ai-development/reduce-token-usage-claude-code-codex-cursor/" rel="noopener noreferrer"&gt;reducing token usage in Claude Code, Codex and Cursor&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, I really enjoyed this one and I think we can all take something from it.&lt;/p&gt;

&lt;h3&gt;
  
  
  From Code to Outcomes (&lt;a href="https://www.linkedin.com/in/nmarcinska" rel="noopener noreferrer"&gt;Natalija Marcinska&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Natalija (BBC Mobile) closed day one, and her talk felt like a nice follow-on from Antoine's, as it came at AI from the product side. Her point was that AI has made it easier than ever to build the wrong thing really quickly. You can build an amazing technical solution, but if your users don't actually need it then all of that time has been wasted.&lt;/p&gt;

&lt;p&gt;She talked about how engineers already make product decisions every day, so we should also be asking whether something should be built at all, and that discovery is part of engineering too. The line that stuck with me was this one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💬 The best code to delete is the code for a feature that would have wasted months.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My takeaways from this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzvcdaeg3jsp5vmvj2hjk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzvcdaeg3jsp5vmvj2hjk.png" alt="Natalija tips" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🗄️ You might not need a backend yet
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CloudKit Public Database as a Backend (&lt;a href="https://www.danijelavrzan.com" rel="noopener noreferrer"&gt;Danijela Vrzan&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Danijela opened day two, and her main advice was to avoid building a backend for as long as possible. So before reaching for one, ask yourself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63ns31tdelx17wa4i7nq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63ns31tdelx17wa4i7nq.png" alt="CloudKit tips" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you do need shared data, the CloudKit Public Database might be the answer. It's managed by Apple, shared across all the users of your app and doesn't need an account system of your own. It's best for static-ish content though, and it isn't the place to store anything sensitive.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Tip:&lt;/strong&gt; Development and Production are separate environments in CloudKit. Don't forget to deploy your schema changes from Development to Production, and be aware that any records you upload to Development won't be carried across. If you've uploaded lots of data, you'll have to upload it all again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This one got me thinking about my own app. Rather than baking configuration straight into the app, I could use the public database alongside the private one to store key content. Definitely one to explore.&lt;/p&gt;




&lt;h2&gt;
  
  
  📣 Building an audience
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Building an Audience for Your Apps (Joe Allen)
&lt;/h3&gt;

&lt;p&gt;Joe, who makes &lt;a href="https://teleprompterpro.com" rel="noopener noreferrer"&gt;Teleprompter Pro&lt;/a&gt;, closed out the conference. For years Joe slowly built up an email list from within his apps, so when he released something new, he let his audience know and got a huge influx of downloads. His point was that an audience is your unfair advantage:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💬 Your competitors don't have &lt;em&gt;your&lt;/em&gt; audience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The obvious worry is "I don't want to spam my users", and Joe's answer to that was... you could just not spam them. 😄 You do need to think about GDPR when you contact users though, and you shouldn't hold your content or features hostage just to get someone's email address.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Register the domains and addresses you send email from in your Apple Developer account (Certificates, Identifiers &amp;amp; Profiles, under Sign in with Apple for Email Communication). Users who Sign in with Apple may be using Private Relay, and without that setup your emails won't reach them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'd love to think more about how we do this at Depop. For my own apps, I'm keeping things private with no email list, so this blog is going to be my way of building an audience instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ The quickfire round
&lt;/h2&gt;

&lt;p&gt;There were plenty of other great talks too, so here's a quick look at the rest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unleash the power of Swift Charts&lt;/strong&gt; (Francesco Marini). This one was all about making your charts readable and accessible. Check your colour palette with &lt;a href="https://projects.susielu.com/viz-palette" rel="noopener noreferrer"&gt;Viz Palette&lt;/a&gt;, use a font you know is readable like &lt;a href="https://fonts.google.com/specimen/Lexend" rel="noopener noreferrer"&gt;Lexend&lt;/a&gt; or &lt;a href="https://opendyslexic.org" rel="noopener noreferrer"&gt;OpenDyslexic&lt;/a&gt;, format your legend and axes, and pick the right mark for the job (bar or line?). He also showed &lt;a href="https://developer.apple.com/documentation/tabulardata" rel="noopener noreferrer"&gt;TabularData&lt;/a&gt;, which is really handy for loading CSV and JSON into a &lt;code&gt;DataFrame&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CarPlay from Zero&lt;/strong&gt; (&lt;a href="https://eyadkelleh.com" rel="noopener noreferrer"&gt;Eyad Kelleh&lt;/a&gt; &amp;amp; &lt;a href="https://www.linkedin.com/in/maurice-pfurr" rel="noopener noreferrer"&gt;Maurice Pfurr&lt;/a&gt;). Eyad and Maurice built &lt;a href="https://www.chargeasmile.com" rel="noopener noreferrer"&gt;Charge a Smile&lt;/a&gt; to compare EV charging prices. CarPlay apps are built from Apple's templates rather than custom UI, and the entitlement you request decides which ones you get.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vapor 5 is actually here&lt;/strong&gt; (&lt;a href="https://www.timc.dev" rel="noopener noreferrer"&gt;Tim Condon&lt;/a&gt;). Vapor 4 has been around since 2020 with over 300 releases, so this is a big one! Vapor 5 focuses on performance, structured concurrency throughout and macro-based routing. &lt;a href="https://blog.vapor.codes/posts/vapor-5-beta/" rel="noopener noreferrer"&gt;The beta is out now&lt;/a&gt; and I'm keen to give the macro-based routing a go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Beyond Boilerplate: Production-Ready Swift Macros&lt;/strong&gt; (&lt;a href="https://kevinhomorales.com" rel="noopener noreferrer"&gt;Kevin Morales&lt;/a&gt;). Macros are great for stable, repeated patterns, but if the code changes often, or you'd only be saving a few lines, it's probably not worth it. I'm wondering whether there are some custom macros I could use for validation. &lt;a href="https://github.com/KevinhoMorales/BeyondBoilerplate-SwiftMacros" rel="noopener noreferrer"&gt;Sample code here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who Let the App Intents Out?&lt;/strong&gt; (&lt;a href="https://clairerimel.github.io" rel="noopener noreferrer"&gt;Claire Sivadier&lt;/a&gt;). App Intents let your app's actions run from Siri, Shortcuts and Apple Intelligence, and with the new Siri relying on them they're well worth a look. Claire's app &lt;a href="https://www.peticle.app" rel="noopener noreferrer"&gt;Peticle&lt;/a&gt; shows them off well.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why Does Our Swift Code Work?&lt;/strong&gt; (&lt;a href="https://freddi.dev" rel="noopener noreferrer"&gt;Yuki Aki&lt;/a&gt;). I loved the analogy here: the compiler is the safe road and the runtime is the car driving along it. Yuki walked us through the pipeline from &lt;code&gt;.swift&lt;/code&gt; to AST, type-checked AST, raw SIL, canonical SIL, LLVM IR and finally a &lt;code&gt;.o&lt;/code&gt; file. It made me think more about how I structure my code, and how much the compiler has to work out in a single expression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Getting physical: Using Swift for 3D printing&lt;/strong&gt; (&lt;a href="https://github.com/ebariaux" rel="noopener noreferrer"&gt;Eric Bariaux&lt;/a&gt;). With &lt;a href="https://github.com/tomasf/Cadova" rel="noopener noreferrer"&gt;Cadova&lt;/a&gt; you can design 3D-printable models in Swift, SwiftUI-style, and watch them update in real time in CadovaViewer, a bit like a SwiftUI preview. This one is purely for fun, but I'm definitely giving it a go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swift Meets Kotlin&lt;/strong&gt; (&lt;a href="https://github.com/sorunokoe" rel="noopener noreferrer"&gt;Yeskendir Salgara&lt;/a&gt;). Trackman shares its Domain and Data layers through Kotlin Multiplatform and keeps the UI and Presentation layers in native Swift, using &lt;a href="https://github.com/touchlab/SKIE" rel="noopener noreferrer"&gt;SKIE&lt;/a&gt; to make the bridge between them feel more like Swift. Even if you never use KMP, it's a good reminder that getting your layering right matters in any architecture.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ What I'm going to try
&lt;/h2&gt;

&lt;p&gt;So after two days of talks, here's what I'm taking away to try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Playing around with &lt;code&gt;TextRenderer&lt;/code&gt; effects, starting with Prismic&lt;/li&gt;
&lt;li&gt;Adding App Intents for the main actions in my own app, and thinking about how I can future-proof it with all the Siri changes coming in&lt;/li&gt;
&lt;li&gt;Considering the CloudKit Public Database for storing information that all users can use&lt;/li&gt;
&lt;li&gt;Building an audience through this blog (no spam, I promise)&lt;/li&gt;
&lt;li&gt;The Vapor 5 beta, and maybe a 3D print designed in Swift&lt;/li&gt;
&lt;li&gt;And after Frank's talk, releasing something new in 2026&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lot of these are going to end up in my side project, &lt;strong&gt;Second Skin&lt;/strong&gt;. It's an iOS app for keeping track of your tattoos: the pieces you have, the ideas you're collecting, the sessions you've booked and your aftercare routine. It's built in SwiftUI with no accounts and no servers, as everything syncs through your own iCloud, so Danijela's talk came at a pretty good time. It's still early days, but hopefully this is the something new that Frank's talk pushed me to release. I'll be writing more about building it here, so watch this space! 👀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18zekxytyc6ohgjmpu1z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18zekxytyc6ohgjmpu1z.jpg" alt="Swift Leeds farewell picture" width="800" height="1067"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Built by humans. A fitting way to close a conference where AI came up in so many of the talks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Thanks to everyone who organised, spoke at and came along to SwiftLeeds this year, it was another great one. See you all at number seven! If you were there, I'd love to hear what your favourite talk was in the comments.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
      <category>techtalks</category>
      <category>career</category>
    </item>
    <item>
      <title>Introduction to Swift! 🚀 (for complete beginners)</title>
      <dc:creator>Andy Lawler</dc:creator>
      <pubDate>Wed, 26 Feb 2020 15:53:30 +0000</pubDate>
      <link>https://dev.to/andylawler/introduction-to-swift-for-complete-beginners-c07</link>
      <guid>https://dev.to/andylawler/introduction-to-swift-for-complete-beginners-c07</guid>
      <description>&lt;h1&gt;So you want to get started with swift but don't know where to start? 🤔 &lt;/h1&gt;

&lt;p&gt;This will be the perfect introduction to Swift. Firstly, let's open up a playground so we have a space to practice writing our code. To do this, open Xcode and then click 'create new playground'. Just name your playground and you are off.&lt;/p&gt;

&lt;p&gt;The first thing you will spot is the line at the very top. UIKit is simply the framework which holds all of the components to build the apps you love. UIKit holds all the information on components such as buttons, labels, views and even controllers.&lt;/p&gt;

&lt;h2&gt; Let's get into the code! 🛠&lt;/h2&gt;

&lt;p&gt;Quickly before we start. I will not be covering printing out values. In Swift it's as easy as doing.&lt;/p&gt;

&lt;p&gt;One extra tip: You can use () in swift to add variables inside of speech marks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello World!🚀"&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Hello World!🚀&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is the number &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// This is the number 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt; Variables 🌦 &lt;/h3&gt;

&lt;p&gt;You might notice the var keyword instantly. Swift uses both variables and constants. Unlike languages like Java for example, swift can recognise types of variables so they do not always need to be pre-defined. You can instead use 'var' for variables that can change and 'let' for constants that will not change. Let's see an example of this!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;canChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;notChanging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="c1"&gt;// we could now do &lt;/span&gt;
&lt;span class="n"&gt;canChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="c1"&gt;// this would change the variable. Whereas, if we did&lt;/span&gt;
&lt;span class="n"&gt;notChanging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="c1"&gt;// we would get an error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing to note, you can pre-define variables in Swift, if you want to do so, use this general syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that I've introduced variables the best way to go next is to talk about data types in Swift.&lt;/p&gt;

&lt;h3&gt; Data Types ✍️&lt;/h3&gt;

&lt;p&gt;Data types are always important in any programming language. With this blog, I'm assuming you have no prior programming knowledge so I will explain exactly what each type is with examples.&lt;/p&gt;

&lt;h4&gt; Integers &lt;/h4&gt;

&lt;p&gt;Integers in Swift are the exact same as integers in real life. If we want to store an integer we simply use the same process as specified above. We use either var or let and then assign an integer to that variable. Integers need to be wholes numbers. Luckily, if you need to represent as a decimal you could also use floats which we will cover later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;
&lt;span class="c1"&gt;// assigning the integer 21 to the variable age&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important note: If you would like to represent binary numbers, hex numbers or even octal numbers. You can do this! I will link to the Swift documentation which has more information on this. &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html" rel="noopener noreferrer"&gt;https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt; Strings &lt;/h4&gt;

&lt;p&gt;Strings are used to store words/character. In Swift we will use them to store text we can then use throughout our apps. Strings in swift are fairly simple. Remember, Swift can detect what data type a variable is so you do not need to define it if you don't want to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Andrew"&lt;/span&gt;
&lt;span class="c1"&gt;// my name is now Andrew&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; Floats &lt;/h4&gt;

&lt;p&gt;Floating Point numbers are used when you want to store numbers that have decimal places. We use them to show off these numbers and they are often used for mathematics inside languages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;
&lt;span class="c1"&gt;// pi is now a float, not an integer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; Booleans &lt;/h4&gt;

&lt;p&gt;Booleans are used in Swift to store either True or False values. Booleans are useful when you want to check conditions. The main thing to remember with Booleans is that they are always either True or False, nothing else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;thisArticleIsAwesome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="c1"&gt;// as you can see this is now true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; Optionals &lt;/h4&gt;

&lt;p&gt;Optionals are one of the key features of Swift which most people will not have seen before! An optional is when a value could or could not have a value. Optionals are really useful when defining variables that may be null. I won't go into any more detail than this. I'll show you what defining an optional will look like. With optionals, you have to define the type of the variable before hand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="c1"&gt;// a is now an optional integer&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="c1"&gt;// a = Optional(5) &amp;lt;- this 5 needs to be unwrapped.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just remember that if you define an optional and then assign a value to it, you will need to unwrap it. Let's see what unwrapping is!&lt;/p&gt;

&lt;h5&gt; Unwrapping Optionals &lt;/h5&gt;

&lt;p&gt;We have three different methods for unwrapping optionals that we could use. Force-Unwrapping, Optional-Chaining or Nil Coalescing. There are other ways of unwrapping but these are the main ones. Let's see what they are all about.&lt;/p&gt;

&lt;h6&gt; Force Unwrapping &lt;/h6&gt;

&lt;p&gt;Force unwrapping is when you append a ! onto the end of an optional to unwrap it to obtain its true value. The one thing to be aware of with force unwrapping is that it's very risky. It's only really a good idea to unwrap it using this method if you know the variable should have a value. If it doesn't and you force unwrap your program will crash. Let's look at an example!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints Optional(10)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt; Optional Chaining &lt;/h6&gt;

&lt;p&gt;Optional chaining is using the ? operator to carry the optional value to retrieve some other value. This may not make complete sense so let's take a look at an example!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Programmer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;favouriteWebsite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DevTo&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;DevTo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;favouriteArticle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"this current article"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;Andy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Programmer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kt"&gt;Andy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;favouriteWebsite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DevTo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Andy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;favouriteWebsite&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;favouriteArticle&lt;/span&gt; 
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints this current article&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to understand with this. We are chaining the optional of favouriteWebsite to then access the favourite Article. As you can see, we have assigned Andy.favouriteWebsite to DevTo. If you don't do this, the optional would still be nil, imagine the code without that line. Favourite website wouldn't be linked to anything at all. If you now look at the example line you can see us use the ?. This simply means we're chaining the optional. You can then see me use ! in the print statement to unwrap the optional. Even though favouriteArticle isn't an optional, as we've chained the value will be an optional.&lt;/p&gt;

&lt;h6&gt; Nil Coalescing &lt;/h6&gt;

&lt;p&gt;Nil Coalescing is using the double ?? operator to give a default value to a variable when you attempt to unwrap it. If the variable turns out to be nil, the default value specified is used instead. Let's look at an example!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints 10 as a is not nil&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints 6 as b is currently nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt; Collection Types 📦&lt;/h3&gt;

&lt;h4&gt; Arrays &lt;/h4&gt;

&lt;p&gt;Arrays are simply storage areas where you can store items/values to then use throughout your code. Arrays can be of many types and you can even create types to store in them. Let's take a look at an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;integerStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
&lt;span class="n"&gt;integerStorage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;integerStorage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// or&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;integerStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// you could specify type 'var integerStorage: [Int]'&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;chosenInt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;integerStorage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Array values can be indexed as shown above, array indexes start at 0 and not 1. So your index values are always '0 .. count-1'.&lt;/p&gt;

&lt;h4&gt; Dictionaries &lt;/h4&gt;

&lt;p&gt;Dictionaries are used when you want a key:value pair. This means you can store one value that links to another value. Let's take a look!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Andy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Sophia"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;myAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Andy"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myAge&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints out 21&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Values taken from dictionaries are always optional. You will need to unwrap them.&lt;/p&gt;

&lt;h4&gt; Sets &lt;/h4&gt;

&lt;p&gt;Sets are useful when dealing with types that you would like to query and or use mathematical set theory. Let's look at some basic examples and then look at the theory we could use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;ourSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;ourSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Does our set contain 10? &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;ourSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints does our set contain 10? true&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Set count: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;ourSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints set count: 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples of set theory: Union, Intersection, Subtracting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Union allows you to join two sets together&lt;/li&gt;
&lt;li&gt;Intersection allows you to find common elements&lt;/li&gt;
&lt;li&gt;Subtraction allows you to subtract one set from another&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt; Tuples &lt;/h4&gt;

&lt;p&gt;Tuples are useful when you need to store values quickly but don't need something like an array or dictionary. As you can see, they look different to the other storage types but they are incredibly useful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;thisCourse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Swift Tutorial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This course is a &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;thisCourse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; and it has a rating of &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;thisCourse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rating&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// This course is a Swift Tutorial and it has a rating of 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt; Operators ➕&lt;/h3&gt;

&lt;p&gt;Now that you know how to define and store your values, we should talk about what you can do with them!&lt;/p&gt;

&lt;h4&gt; Addition/Subtraction &lt;/h4&gt;

&lt;p&gt;I won't say much about addition and subtraction. In Swift it's fairly simple. Let's jump straight into the examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints 7&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; Multiplication/Division &lt;/h4&gt;

&lt;p&gt;Same as above. Multiplication and Division is fairly simply inside Swift. Let's look at the examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// prints 10&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints 2.5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; W?T:F (Ternary) &lt;/h4&gt;

&lt;p&gt;This operator get's the name W?T:F this stands for what, true, false. This is a good way to remember it! This operator is used when you want to check something and then apply different values for true or false. Let's take a look at an example!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"True"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"False"&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; Unary &lt;/h4&gt;

&lt;p&gt;The unary operator is simply used as a NOT operator. You use it show that you wan't the opposite of what it's used in conjunction with. Let's look at an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; Compound Assignment Operator &lt;/h4&gt;

&lt;p&gt;This is where swift is a tiny bit different to some other languages. In lot's of other programming languages there is a ++ or -- operator. This operator is used to add 1 or remove 1 from a variable. In swift this is not the case. Instead you must use += or -=. Let's look at some examples for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints 20&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// prints 9&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are plenty of other operators in Swift but they are all similar to other programming languages. For the full list, check out the documentation below. &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/BasicOperators.html" rel="noopener noreferrer"&gt;https://docs.swift.org/swift-book/LanguageGuide/BasicOperators.html&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt; Control Flow 🌊 &lt;/h3&gt;

&lt;p&gt;Control flow is something you will be using all the time when writing code in any language. It allows you to query, look through values and do so much more. Let's take a look at it in Swift.&lt;/p&gt;

&lt;h4&gt; For loop &lt;/h4&gt;

&lt;p&gt;For loops are used to loop through certain values. You can loop through arrays, dictionaries, sets or just through ranges. Let's take a look at some examples to see how they work!&lt;/p&gt;

&lt;p&gt;In our first example we loop through our names array using 'name' as the iterator. It could be called anything, it's doesn't have to be called names. We just call it names to the code itself is more readable. This loop will now go through each value in this loop and print them out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Andy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Brad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// prints Andy Brad John&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this second example we are using ranges to print out numbers in a specified range. You can clearly see how the code below is printing from 0 to 4. This occurs because we use the 0..&amp;lt;5 operator. This simply says go from 0 to less than 5. You could change this to anything for example ... or ..&amp;gt; etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// prints 0 1 2 3 4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; While loop &lt;/h4&gt;

&lt;p&gt;While statements are loops that run based on a condition. For example, if you start a loop that says 'while a&amp;gt;5' the loop will keep running until a is &amp;lt;=5. These loops really useful. Let's look at how we could use them!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// prints 10 9 8 7 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip: You can use 'break' inside loops to stop them at any time. Let's look at an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// prints 10 and then breaks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt; If statement &lt;/h4&gt;

&lt;p&gt;If statements are really important when it comes to checking conditions and making decisions. Let's take a look at some examples.&lt;/p&gt;

&lt;p&gt;Syntax: If, else if, else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Yes, a is 10"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No, a is not 10"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"b is 3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"b is 4"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"b is something else"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// prints Yes, a is 10 and b is something else&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are interested in learning a more advanced version of control flow that acts like an if statement, take a look at this documentation to learn about guard statements. &lt;a href="https://docs.swift.org/swift-book/ReferenceManual/Statements.html" rel="noopener noreferrer"&gt;https://docs.swift.org/swift-book/ReferenceManual/Statements.html&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt; Switch statement &lt;/h4&gt;

&lt;p&gt;Switch statements are statements just like the others but they use control expressions and then cases. You can assign a default case and then cases for any possible value you want. This may not make complete sense so let's look at a basic example!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Yes a is 10"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No a is not 10"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// prints Yes a is 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above is a really simple example of Switch statements. You can also use enums for Switch statements and I haven't covered enums in this article. If you want to learn more, check it out here: &lt;a href="https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html" rel="noopener noreferrer"&gt;https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt; Challenge Yourself! 🤓&lt;/h3&gt;

&lt;p&gt;I'll include some challenges here to see how much you have learned throughout. I'll post the code below the conclusion so you can check your work!&lt;/p&gt;

&lt;h5&gt; Task 1️⃣ &lt;/h5&gt;

&lt;p&gt;For this task, I would like to to write a simply program that can take an input of a shopping list and print out it's contents. The printed out list should look like this. Tip, use an array to manage the items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;Apples&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;Pears&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;Lemons&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="kt"&gt;Oranges&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;extension: Could you print how many items the user has overall?&lt;/p&gt;

&lt;h2&gt; Conclusion 🥳&lt;/h2&gt;

&lt;p&gt;I hope this was a good introduction to the language so you can now play around! If enough people are interested I'll make a video introducing Xcode and how to use it if you've never used it before. I hope everyone enjoyed this post!&lt;/p&gt;

&lt;h2&gt; Answers to the tasks 👨‍🏫 &lt;/h2&gt;

&lt;h3&gt; Task 1️⃣ &lt;/h3&gt;

&lt;p&gt;Just remember, the loop may print in a different order. This is perfectly fine!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;shoppingList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Apples"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Pears"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lemons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Oranges"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;shoppingList&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// extension: print(shoppingList.count)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ios</category>
      <category>swift</category>
    </item>
    <item>
      <title>Programmatic Constraints in Swift 📏</title>
      <dc:creator>Andy Lawler</dc:creator>
      <pubDate>Thu, 20 Feb 2020 22:48:12 +0000</pubDate>
      <link>https://dev.to/andylawler/programmatic-constraints-in-swift-kj</link>
      <guid>https://dev.to/andylawler/programmatic-constraints-in-swift-kj</guid>
      <description>&lt;p&gt;Have you always wanted to learn how to constrain your views and elements in Swift programatically and want to use no-libraries, well you are in the best place. This method of writing constraints is quite tedious in comparison to the likes of SnapKit but you will learn the fundamentals of constraints and then you can apply this knowledge to libraries like SnapKit in the future.&lt;/p&gt;

&lt;h2&gt; Let's get started 😀 &lt;/h2&gt;

&lt;p&gt;Firstly, we need to understand the key types of Anchors and what they all mean! Let's list the types out.&lt;/p&gt;

&lt;h4&gt; Types of Anchors ⚓️ &lt;/h4&gt;

&lt;p&gt;To constrain programmatically you must constrain to the pre-specified anchors that are provided for us to use. These are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Top (Anchor at the top of the view)&lt;/li&gt;
&lt;li&gt;Bottom (Anchor at the bottom of the view)&lt;/li&gt;
&lt;li&gt;Leading (Anchor at the left of the view)&lt;/li&gt;
&lt;li&gt;Trailing (Anchor at the right of the view)&lt;/li&gt;
&lt;li&gt;CenterX (Anchor on the centre of the X axis)&lt;/li&gt;
&lt;li&gt;CenterY (Anchor on the centre of the Y axis)&lt;/li&gt;
&lt;li&gt;Width (Anchor determining Width)&lt;/li&gt;
&lt;li&gt;Height (Anchor determining Height)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember: Usually you will need four constraints, never less. If you have more than four constraints you should see if you can improve the way you are constraining your elements.&lt;/p&gt;

&lt;p&gt;Now, let's look at the process of adding constraints and we can then explore examples of each type!&lt;/p&gt;

&lt;h4&gt; Process of adding constraints 👷🏼‍♂️&lt;/h4&gt;

&lt;p&gt;It's usually good practice to add your constraints directly under your view.addSubview(view) code. I usually have a process for adding constraints to elements. It looks a little bit like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjpho92s5gqbkt44td22r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjpho92s5gqbkt44td22r.png" alt="Code for adding constraints" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should always remember to make sure to add the new view as a subView of the main view and then make sure you change the bool as shown above. This bool allows us to write out our own custom programmatic constraints. A common mistake is to not make this false.&lt;/p&gt;

&lt;h4&gt; Examples of constraints using our Anchors &lt;/h4&gt;

&lt;p&gt;tip: Something I learned from Sean Allen is that you can define a padding type as a CGFloat and use this variable instead of manually inputting your constants. This allows you to change your UI from one position. Example below!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fztrztq0tsdj2gexlpegb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fztrztq0tsdj2gexlpegb.png" alt="Padding" width="700" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can delve into the examples. We will go through some examples and show different ways they could be implemented. Take into account there are many different types of constraints, eg: constants, multipliers. We are going to use constants, just take into account that where you see constant it could also be a multiplier if you needed it to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fadxzqloxh1fcqwg9gtuu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fadxzqloxh1fcqwg9gtuu.png" alt="Constraint Types" width="797" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt; Top Anchor &lt;/h5&gt;

&lt;p&gt;This example below links the example view to the top of the main view with a distance of 40. this is a common way of setting up this type of constraint. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3wljfei5t1r0vdzhobia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3wljfei5t1r0vdzhobia.png" alt="Top Anchor" width="798" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;tip: add safeAreaLayoutGuide in between view and topAnchor to pin to the safe area not the top of the view!&lt;/p&gt;

&lt;h5&gt; Bottom Anchor &lt;/h5&gt;

&lt;p&gt;This example below constrains the example view to the bottomAnchor with a distance of 10. Take into account that the number needs to be negative as we want the view to be away from the anchor not past it. This will make more sense when we do leading and trailing anchors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn8fqeyn6p6whxvn1cevw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn8fqeyn6p6whxvn1cevw.png" alt="Bottom Anchor" width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;tip: add safeAreaLayoutGuide in between view and bottomAnchor to pin to safe area once again.&lt;/p&gt;

&lt;h5&gt; Leading Anchor &lt;/h5&gt;

&lt;p&gt;The leading anchor is the anchor on the left hand side of the screen. The left hand side is the leading anchor as we imagine we are looking from left to right. With this knowledge we can verify that the trailing anchor is the anchor to the right. Leading anchor constants do not need to be negative as we want our view to be pinned to the right of the anchor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyssnj857jjjvhtzo7bxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyssnj857jjjvhtzo7bxa.png" alt="Leading Anchor" width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt; Trailing Anchor &lt;/h5&gt;

&lt;p&gt;Key thing with trailing anchors is that the constant must be negative not positive as you are wanting your view to be x pixels behind the Anchor itself. The example below is the line we would add to make this possible. This examples shows us pinning a trailing anchor&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhcryc042w9o4h4b95k66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhcryc042w9o4h4b95k66.png" alt="Trailing Anchor" width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt; CenterX Anchor / CenterY Anchor &lt;/h5&gt;

&lt;p&gt;CenterX and CenterY Anchors are fairly self explanatory. We use them to center views when we need them to be fixed in an axis. These two anchors are useful for having an image in the exact center of the screen. I will show examples of pinning to the CenterX Anchor and also the CenterY Anchor but with a constant.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcwfq349q6scjcpdszjak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcwfq349q6scjcpdszjak.png" alt="Center X Y Anchor" width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt; Width Anchor / Height Anchor &lt;/h5&gt;

&lt;p&gt;Width and Height Anchors are quite self explanatory. These constraints allow you to add a width and height to your views. I will show you an example below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F95ef4o5gta59fd4kvuqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F95ef4o5gta59fd4kvuqq.png" alt="Width Height Anchor" width="799" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt; Full Examples using what we have learned! ✍️ &lt;/h4&gt;

&lt;p&gt;Now let's put into practice what we've learned! I will include three full examples below showing valid constraints along with what they look like on the device!&lt;/p&gt;

&lt;h5&gt; Example 1 &lt;/h5&gt;

&lt;p&gt;This example shows how we can create a View and then pin the view to the edges of the phone. I've made the view red so you can see what's happening.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu2f3uhhpmytdk2iarcy2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu2f3uhhpmytdk2iarcy2.png" alt="Example 1 Code" width="799" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can see what's happening on the phone in red!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu3pvfg8n26ak96c2wsrq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu3pvfg8n26ak96c2wsrq.png" alt="Example 1 Phone" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt; Example 2 &lt;/h5&gt;

&lt;p&gt;This example shows how we can pin a view to the centre of the phone and then add a width and height to it, you could use this for main screen logos! I used a variable for the box size so we can easily resize it if needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8mlpngslx950i9tqeom9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8mlpngslx950i9tqeom9.png" alt="Example 2 Code" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can see what's happening on the phone in blue!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz5sr5zyi7bh0hhqce9zb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz5sr5zyi7bh0hhqce9zb.png" alt="Example 2 Phone" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt; Example 3 &lt;/h5&gt;

&lt;p&gt;This example shows how we can create two views and stack them without using a stack view. This could be used to create some interesting designs! Look at the way I've pinned to the first views bottom anchor in the second views top anchor constraint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyr0p4hv8r6npjbuw25bg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyr0p4hv8r6npjbuw25bg.png" alt="Example 3 Code" width="800" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can see what's happening on the phone in green and pink!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffbroa4v4ywqylpsi53e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffbroa4v4ywqylpsi53e1.png" alt="Example 3 Phone" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt; Review 🥳&lt;/h4&gt;

&lt;p&gt;Now you have seen examples of how to add constraints programmatically in Swift!&lt;/p&gt;

&lt;p&gt;If you have any additions for this post please do leave it in the comments, this is my first ever post so feedback would be appreciated! &lt;/p&gt;

</description>
      <category>swift</category>
      <category>appdevelopment</category>
      <category>ios</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
