<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Swift Dev Journal</title>
    <link>https://swiftdevjournal.com/</link>
    <description>Recent content on Swift Dev Journal</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 11 Mar 2026 13:19:03 -0500</lastBuildDate>
    <atom:link href="https://swiftdevjournal.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Composing Parsers with the swift-parsing Library</title>
      <link>https://swiftdevjournal.com/posts/composing-parsers/</link>
      <pubDate>Wed, 11 Mar 2026 13:19:03 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/composing-parsers/</guid>
      <description>&lt;p&gt;One of the selling points of the &lt;a href=&#34;https://github.com/pointfreeco/swift-parsing&#34;&gt;swift-parsing library&lt;/a&gt; is that you can create small parsers that do one simple thing and combine them to parse more complex data. This article shows how to combine smaller parsers to create a larger parser.&lt;/p&gt;&#xA;&lt;h2 id=&#34;creating-a-parser&#34;&gt;Creating a parser&lt;/h2&gt;&#xA;&lt;p&gt;A swift-parsing parser is a struct that conforms to the &lt;code&gt;Parser&lt;/code&gt; protocol. Conform to the protocol by creating a &lt;code&gt;body&lt;/code&gt; property that returns a parser that conforms to &lt;code&gt;Parser&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ParserName&lt;/span&gt;: Parser {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Parser&amp;lt;T, U&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that the struct and the &lt;code&gt;body&lt;/code&gt; property have &lt;code&gt;public&lt;/code&gt; access. The swift-parsing library requires &lt;code&gt;public&lt;/code&gt; access to parse the data. If you forget to add &lt;code&gt;public&lt;/code&gt;, you will get build errors.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;T&lt;/code&gt; type is the input type the parser takes. Most parsers use the &lt;code&gt;Substring&lt;/code&gt; type as the input type. If you are parsing lots of data and require maximum performance, use &lt;code&gt;UTF8View&lt;/code&gt; as the input type. The examples in this article use substrings.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;U&lt;/code&gt; type is the output type the parser returns. The return type can be a simple type, such as an integer or Boolean value, or it can be more complex, such as one of your app&amp;rsquo;s structs or classes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;parsing-example&#34;&gt;Parsing example&lt;/h2&gt;&#xA;&lt;p&gt;The example in this article parses the output of the Jujutsu version control system&amp;rsquo;s &lt;code&gt;jj show&lt;/code&gt; command that shows details of a change. A Jujutsu change is similar to a git commit. The output of the &lt;code&gt;jj show&lt;/code&gt; command looks similar to the following text:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Commit ID: 73d31d1766b0bc211d22b87f2f911429f3846a61&#xA;Change ID: lyrzonnxolkpxytwwykkqpvvlqmvlxqm&#xA;Author   : Bob Ducca &amp;lt;ducca@example.com&amp;gt; (2025-06-23 18:04:09)&#xA;Committer: Bob Ducca &amp;lt;ducca@example.com&amp;gt; (2025-06-23 18:04:49)&#xA;&#xA;  Add sentence that you have to set a bookmark and push.&#xA;  &#xA;  Add a paragraph so the change description has multiple paragraphs, which is good for unit testing change descriptions.&#xA;&#xA;Modified regular file GitHub.md:&#xA;    ...&#xA;   4    4: &#xA;   5    5: ## Working with Existing GitHub Repo&#xA;   6    6: &#xA;   7    7: In most cases you have an existing GitHub repo. This is what you do.&#xA;        8: &#xA;        9: You have to set a bookmark and call `jj git push`.&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Change&lt;/code&gt; struct stores the change information.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Change&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; changeId: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; author: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; timestamp: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; description: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;parsing-the-change-id&#34;&gt;Parsing the change ID&lt;/h3&gt;&#xA;&lt;p&gt;Parsing the change ID involves the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Skip everything through the text &lt;code&gt;Change ID:&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Skip any additional whitespace.&lt;/li&gt;&#xA;&lt;li&gt;Capture everything up to the end of the line.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ChangeId&lt;/span&gt;: Parser {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Parser&amp;lt;Substring, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Substring&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Change ID:&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Whitespace()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Capture everything until the next whitespace.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;parsing-the-author&#34;&gt;Parsing the author&lt;/h3&gt;&#xA;&lt;p&gt;Parsing the author requires the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Skip everything through the text &lt;code&gt;Author&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Skip whitespace.&lt;/li&gt;&#xA;&lt;li&gt;Skip the colon.&lt;/li&gt;&#xA;&lt;li&gt;Skip more whitespace.&lt;/li&gt;&#xA;&lt;li&gt;Capture everything up to the &lt;code&gt;&amp;lt;&lt;/code&gt; character, which marks the start of the author email address.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ChangeAuthor&lt;/span&gt;: Parser {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Parser&amp;lt;Substring, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Substring&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Author&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Whitespace()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Capture everything until the start of the email address.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; &amp;lt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;parsing-the-timestamp&#34;&gt;Parsing the timestamp&lt;/h3&gt;&#xA;&lt;p&gt;The timestamp looks like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(2025-06-23 18:04:09)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Parsing the timestamp involves the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Skip everything through the first left parenthesis.&lt;/li&gt;&#xA;&lt;li&gt;Capture everything up to the next right parenthesis.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ChangeTimestamp&lt;/span&gt;: Parser {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Parser&amp;lt;Substring, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Substring&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;parsing-the-change-description&#34;&gt;Parsing the change description&lt;/h3&gt;&#xA;&lt;p&gt;The change description starts after the first blank line. The description ends with a blank line and one of the following phrases:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Modified regular file&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Added regular file&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Removed regular file&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Start by writing a parser for each possible end of a description.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; modifiedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Modified regular file&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; addedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Added regular file&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; removedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Removed regular file&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the &lt;code&gt;OneOf&lt;/code&gt; parser to capture everything until you reach one of the possible ends of the description. Use the &lt;code&gt;Rest()&lt;/code&gt; parser as a fallback if you hit the end of the text before reaching one of the possible description ends.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ChangeDescription&lt;/span&gt;: Parser {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Parser&amp;lt;Substring, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Substring&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; modifiedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Modified regular&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; addedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Added regular&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; removedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Removed regular&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Skip everything to the first blank line and any whitespace after the blank line.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Whitespace()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Capture everything up to one of the phrases that marks the end of a description.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    OneOf {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      modifiedFile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      addedFile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      removedFile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Rest()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;composing-a-change-parser&#34;&gt;Composing a change parser&lt;/h3&gt;&#xA;&lt;p&gt;The last part is to build a change parser that runs the parsers for each piece of the change and returns a &lt;code&gt;Change&lt;/code&gt; instance.&lt;/p&gt;&#xA;&lt;p&gt;The tough part is building the &lt;code&gt;Change&lt;/code&gt; instance. Each of the smaller parsers returns a string. How do you build a &lt;code&gt;Change&lt;/code&gt; instance from a group of strings?&lt;/p&gt;&#xA;&lt;p&gt;Add a local variable for the change to the &lt;code&gt;body&lt;/code&gt; property. After running each parser, add a &lt;code&gt;map&lt;/code&gt; modifier and supply a closure to fill the change&amp;rsquo;s property with the output from the parser. Return the local variable after running the parsers.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ChangeParser&lt;/span&gt;: Parser {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Parser&amp;lt;Substring, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Change&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; change = Change()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ChangeId()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .map { id &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          change.changeId = String(id)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ChangeAuthor()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .map { author &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          change.author = String(author)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ChangeTimestamp()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .map { time &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          change.timestamp = String(time)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ChangeDescription()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .map { message &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          change.description = String(message)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; change&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#75715e&#34;&gt;// End Parse block&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#75715e&#34;&gt;// End body&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Measure App Launch Time with Instruments</title>
      <link>https://swiftdevjournal.com/posts/measure-app-launch-time/</link>
      <pubDate>Tue, 10 Feb 2026 12:34:53 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/measure-app-launch-time/</guid>
      <description>&lt;p&gt;Take the following steps to measure your app&amp;rsquo;s launch time with Instruments:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Press Cmd-I or choose Product &amp;gt; Profile to profile your app.&lt;/li&gt;&#xA;&lt;li&gt;Select the App Launch template when Instruments launches.&lt;/li&gt;&#xA;&lt;li&gt;Click the Choose button.&lt;/li&gt;&#xA;&lt;li&gt;Click the Record button to start profiling.&lt;/li&gt;&#xA;&lt;li&gt;Select the item with the name of your app from the timeline pane.&lt;/li&gt;&#xA;&lt;li&gt;Press Cmd-4 to open the App Lifecycle section.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AppLifecycle.png&#34; alt=&#34;App Lifecycle Section&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The App Lifecycle section lists the app&amp;rsquo;s launch steps and how long each step took.&lt;/p&gt;&#xA;&lt;h2 id=&#34;do-you-want-to-learn-more-about-instruments&#34;&gt;Do you want to learn more about Instruments?&lt;/h2&gt;&#xA;&lt;p&gt;I wrote a book, &lt;em&gt;Profiling Swift Apps&lt;/em&gt;, that shows you how to use Instruments to find and fix problems in your code. The book will help you make apps that run faster and use less memory. You can learn more about the book and download a sample at the following link:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/instruments-book/&#34;&gt;Profiling Swift Apps page&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Add an Open Recent Menu to a SwiftUI app</title>
      <link>https://swiftdevjournal.com/posts/open-recent-menu/</link>
      <pubDate>Thu, 05 Feb 2026 14:00:00 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/open-recent-menu/</guid>
      <description>&lt;p&gt;Why would you need to add an Open Recent menu? The most common reason is you created an app that doesn&amp;rsquo;t use the document architecture, and you want a way for your app&amp;rsquo;s users to access recent items.&lt;/p&gt;&#xA;&lt;p&gt;Adding an Open Recent menu requires you to do the following things:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Use the &lt;code&gt;NSDocumentController&lt;/code&gt; class to track recent items.&lt;/li&gt;&#xA;&lt;li&gt;Add an &lt;code&gt;@Observable&lt;/code&gt; class to hold the recent items so SwiftUI can update the Open Recent menu when its contents change.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;using-nsdocumentcontroller-to-track-recent-items&#34;&gt;Using &lt;code&gt;NSDocumentController&lt;/code&gt; to track recent items&lt;/h2&gt;&#xA;&lt;p&gt;The name &lt;code&gt;NSDocumentController&lt;/code&gt; implies that it works with &lt;code&gt;NSDocument&lt;/code&gt;. However, the parts of &lt;code&gt;NSDocumentController&lt;/code&gt; that deal with the Open Recent menu require only an array of URLs. You can use &lt;code&gt;NSDocumentController&lt;/code&gt; without creating a document app.&lt;/p&gt;&#xA;&lt;p&gt;Use the &lt;code&gt;shared&lt;/code&gt; instance to access the standard document controller.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NSDocumentController.shared&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the &lt;code&gt;recentDocumentURLs&lt;/code&gt; property to access the URLs of the recent items and fill the Open Recents menu. Call the &lt;code&gt;noteNewRecentDocumentURL&lt;/code&gt; function to update the recent items after opening or creating an item. Call the &lt;code&gt;clearRecentDocuments&lt;/code&gt; function to clear the recent items list and clear the Open Recent menu.&lt;/p&gt;&#xA;&lt;h2 id=&#34;initial-version-of-the-open-recent-menu&#34;&gt;Initial version of the Open Recent menu&lt;/h2&gt;&#xA;&lt;p&gt;An initial version of an Open Recent menu looks like the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;OpenRecentMenu&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Environment(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.openWindow) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; openWindow&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Menu(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Open Recent&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ForEach(NSDocumentController.shared.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        recentDocumentURLs, id: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { url &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Button(url.lastPathComponent) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#75715e&#34;&gt;// Item is a class in your app.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; itemToOpen = Item(location: url)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          openWindow(value: itemToOpen)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          NSDocumentController.shared.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            noteNewRecentDocumentURL(url)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Divider()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Button(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Clear Menu&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          NSDocumentController.shared.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            clearRecentDocuments(&lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code creates the Open Recent menu and fills it with recent items. There is one big problem. The Open Recent menu doesn&amp;rsquo;t update until you restart the app.&lt;/p&gt;&#xA;&lt;p&gt;The reason the menu doesn&amp;rsquo;t update is SwiftUI doesn&amp;rsquo;t automatically update the menu when the shared document controller&amp;rsquo;s array of recent items changes.&lt;/p&gt;&#xA;&lt;p&gt;To get the menu to update, you must add an &lt;code&gt;@Observable&lt;/code&gt; class that holds the recent item URLs and pass that class to the menu view.&lt;/p&gt;&#xA;&lt;h2 id=&#34;create-the-observable-class&#34;&gt;Create the &lt;code&gt;@Observable&lt;/code&gt; class&lt;/h2&gt;&#xA;&lt;p&gt;The class has two requirements. First, it needs a property that holds the URLs of the recent items. Second, it needs a function to update the array from the shared document controller.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Observable&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RecentItems&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @MainActor &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; shared = RecentItems()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; items: [URL] = []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(items: [URL]) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.items = items&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @MainActor &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;refresh&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; docControllerRecents = NSDocumentController.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      shared.recentDocumentURLs&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; docControllerRecents &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; items {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      items = docControllerRecents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Supply the value &lt;code&gt;NSDocumentController.shared.recentDocumentURLs&lt;/code&gt; to the &lt;code&gt;RecentItems&lt;/code&gt; initializer to fill the Open Recent menu when your app launches.&lt;/p&gt;&#xA;&lt;p&gt;When you open or add an item in your app, call the &lt;code&gt;refresh&lt;/code&gt; function to update the Open Recent menu.&lt;/p&gt;&#xA;&lt;h2 id=&#34;add-the-observable-class-to-the-menu&#34;&gt;Add the &lt;code&gt;@Observable&lt;/code&gt; class to the Menu&lt;/h2&gt;&#xA;&lt;p&gt;To use your &lt;code&gt;@Observable&lt;/code&gt; class in the menu, you must add a &lt;code&gt;@State&lt;/code&gt; property for the class to the App struct. Pass the value to the menu using a binding. Use the array in your &lt;code&gt;@Observable&lt;/code&gt; class to fill the Open Recent menu.&lt;/p&gt;&#xA;&lt;p&gt;The following code shows the updated Open Recent menu:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;OpenRecentMenu&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Environment(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.openWindow) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; openWindow&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; recents: RecentItems&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Menu(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Open Recent&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ForEach(recents.items, id: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { url &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Button(url.lastPathComponent) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; item = Item(location: url)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          openWindow(value: item)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          NSDocumentController.shared.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            noteNewRecentDocumentURL(url)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          recents.refresh()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Divider()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Button(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Clear Menu&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          NSDocumentController.shared.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            clearRecentDocuments(&lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          recents.refresh()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Supporting SwiftUI Sidebar Selection with Multiple Data Types</title>
      <link>https://swiftdevjournal.com/posts/sidebar-selection/</link>
      <pubDate>Tue, 06 Jan 2026 13:29:32 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/sidebar-selection/</guid>
      <description>&lt;p&gt;When handling the sidebar selection in a SwiftUI app, the usual approach is to add a &lt;code&gt;@State&lt;/code&gt; property to the view to store the selection. The code looks similar to the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; selection: Chapter? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The usual approach works well if all the items in the sidebar have the same data type. What do you do if the sidebar items have different data types?&lt;/p&gt;&#xA;&lt;p&gt;Supporting selection with multiple data types involves the following tasks:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create an enum for the sidebar selection.&lt;/li&gt;&#xA;&lt;li&gt;Use the enum you create as the data type for the selection.&lt;/li&gt;&#xA;&lt;li&gt;Add a &lt;code&gt;.tag&lt;/code&gt; modifier to each list item that holds the item&amp;rsquo;s data type and value.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;creating-the-enum&#34;&gt;Creating the enum&lt;/h2&gt;&#xA;&lt;p&gt;Create an enum for the sidebar selection with a case for each possible data type a sidebar item can have.&lt;/p&gt;&#xA;&lt;p&gt;As an example I&amp;rsquo;m going to show code for an app I&amp;rsquo;m currently making, &lt;a href=&#34;https://checksimsoftware.com/jjewel&#34;&gt;a Mac GUI client for the Jujutsu version control system&lt;/a&gt;. The app&amp;rsquo;s sidebar has multiple items for controlling what appears in the list of changes (commits). The selection can be either a change category (all changes, mutable changes, my changes) or a bookmark (branch). Selecting a bookmark shows its changes.&lt;/p&gt;&#xA;&lt;p&gt;The following code shows the enum for the sidebar selection:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SidebarSelection&lt;/span&gt;: Hashable, Sendable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; change(category: ChangeCategory)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; bookmark(bookmark: Bookmark)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ChangeCategory&lt;/span&gt;: CaseIterable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; allChanges&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; mutableChanges&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; myChanges&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stringValue&lt;/span&gt;() -&amp;gt; String {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .allChanges:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;All Changes&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .mutableChanges:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mutable Changes&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .myChanges:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;My Changes&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Bookmark&lt;/span&gt;: Equatable, Hashable, Codable, Sendable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Other properties removed for clarity.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; name: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; == (lhs: Bookmark, rhs: Bookmark) -&amp;gt; Bool {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      lhs.name == rhs.name&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;using-the-enum-for-the-selection&#34;&gt;Using the enum for the selection&lt;/h2&gt;&#xA;&lt;p&gt;In the sidebar view, add a property to store the selection. The data type is the enum you created.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; selection: SidebarSelection?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;adding-the-tag-modifier&#34;&gt;Adding the .tag modifier&lt;/h2&gt;&#xA;&lt;p&gt;Each list item in the sidebar needs a &lt;code&gt;.tag&lt;/code&gt; modifier so SwiftUI knows what the item represents. The value of the modifier is one of the sidebar selection enum&amp;rsquo;s cases. You must also supply any additional data the enum case requires.&lt;/p&gt;&#xA;&lt;p&gt;The following code shows a sidebar list with sections for change categories and bookmarks:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List(selection: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;selection) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Section(header: Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Changes&amp;#34;&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ForEach(ChangeCategory.allCases, id:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { category &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Text(category.stringValue())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .tag(SidebarSelection.change(category: category))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Section(header: Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Bookmarks&amp;#34;&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ForEach(bookmarks, id:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.name) { bookmark &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Text(bookmark.name)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .tag(SidebarSelection.bookmark(bookmark: bookmark))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Introduction to the Swift Subprocess Package</title>
      <link>https://swiftdevjournal.com/posts/subprocess/</link>
      <pubDate>Mon, 29 Dec 2025 13:12:41 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/subprocess/</guid>
      <description>&lt;p&gt;The Swift language group&amp;rsquo;s &lt;a href=&#34;https://github.com/swiftlang/swift-subprocess&#34;&gt;Subprocess package&lt;/a&gt; lets you spawn processes in Swift apps. The package makes it easier to run Terminal commands and launch command-line programs from Swift apps.&lt;/p&gt;&#xA;&lt;h2 id=&#34;launching-a-program&#34;&gt;Launching a program&lt;/h2&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;run&lt;/code&gt; function to launch a process. In most cases a process will be a Terminal command, a shell script, or a command-line program.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;run&lt;/code&gt; function is asynchronous so you must add &lt;code&gt;await&lt;/code&gt; when calling &lt;code&gt;run&lt;/code&gt;. The function can throw errors so you should wrap the call in a &lt;code&gt;do-catch&lt;/code&gt; block to handle errors.&lt;/p&gt;&#xA;&lt;p&gt;If the program to run is installed on the user&amp;rsquo;s computer, use the &lt;code&gt;.name&lt;/code&gt; parameter and supply the name of the program to run. You must also supply an &lt;code&gt;output&lt;/code&gt; argument to specify how to store the output.&lt;/p&gt;&#xA;&lt;p&gt;The following code runs the &lt;code&gt;ls&lt;/code&gt; command and collects its output in a string:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; result = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; await run(.name(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ls&amp;#34;&lt;/span&gt;), &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    output: .string(limit: &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the &lt;code&gt;standardOutput&lt;/code&gt; property from the result to access the program&amp;rsquo;s output.&lt;/p&gt;&#xA;&lt;h2 id=&#34;launching-a-program-from-a-mac-app-bundle&#34;&gt;Launching a program from a Mac app bundle&lt;/h2&gt;&#xA;&lt;p&gt;If you bundle a command-line program with a Mac Swift app, you can&amp;rsquo;t use &lt;code&gt;.name&lt;/code&gt; to run the program because the program isn&amp;rsquo;t installed on the user&amp;rsquo;s Mac. You must use the &lt;code&gt;.path&lt;/code&gt; parameter and supply a path to the program&amp;rsquo;s location. If you have a URL for the program, use its &lt;code&gt;path&lt;/code&gt; property as the path.&lt;/p&gt;&#xA;&lt;p&gt;The following code runs a program in the app bundle named &lt;code&gt;MyProgram&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; executableLocation: FilePath&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; bundle = Bundle.main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; resourceFolder = bundle.resourceURL&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; executableURL = resourceFolder?.appendingPathComponent(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MyProgram&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;executableLocation = FilePath(executableURL?.path(percentEncoded: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;) ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; result = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; await run(.path(executableLocation), &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    output: .string(limit: &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;passing-arguments&#34;&gt;Passing arguments&lt;/h2&gt;&#xA;&lt;p&gt;Many Terminal commands and command-line programs take arguments. To pass these arguments to the &lt;code&gt;run&lt;/code&gt; function, add an &lt;code&gt;arguments&lt;/code&gt; parameter to the &lt;code&gt;run&lt;/code&gt; function and supply the arguments.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;arguments: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;arg1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;arg2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;arg3&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Subprocess package has an &lt;code&gt;Arguments&lt;/code&gt; data structure for the arguments. If you create a variable to hold a program&amp;rsquo;s arguments, make sure its data type is &lt;code&gt;Arguments&lt;/code&gt; and not an array of strings.&lt;/p&gt;&#xA;&lt;h2 id=&#34;setting-the-working-directory&#34;&gt;Setting the working directory&lt;/h2&gt;&#xA;&lt;p&gt;If you need to set the working directory for a program, add a &lt;code&gt;workingDirectory&lt;/code&gt; argument to the &lt;code&gt;run&lt;/code&gt; function and supply the working directory.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;workingDirectory&lt;/code&gt; argument takes a &lt;code&gt;FilePath&lt;/code&gt; instance, not a URL. If you have a URL, use the &lt;code&gt;URL&lt;/code&gt; struct&amp;rsquo;s &lt;code&gt;path&lt;/code&gt; function to get a file path.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; currentFolder: URL&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; workingDirectory: FilePath&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;workingDirectory = FilePath(currentFolder.path(percentEncoded: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;output-options&#34;&gt;Output options&lt;/h2&gt;&#xA;&lt;p&gt;The examples so far have returned the output as a string. You must specify a length limit for the string. Make sure you set a high enough limit. If the output&amp;rsquo;s length exceeds the limit, the &lt;code&gt;run&lt;/code&gt; function returns no output.&lt;/p&gt;&#xA;&lt;p&gt;Other output options include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A &lt;code&gt;Data&lt;/code&gt; object&lt;/li&gt;&#xA;&lt;li&gt;A file descriptor&lt;/li&gt;&#xA;&lt;li&gt;An array of bytes&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;returning-error-messages&#34;&gt;Returning error messages&lt;/h2&gt;&#xA;&lt;p&gt;If you need to return an error message if the program runs unsuccessfully, add an &lt;code&gt;error&lt;/code&gt; argument to the &lt;code&gt;run&lt;/code&gt; function. The data type for the error message can be one of the output option types: string, &lt;code&gt;Data&lt;/code&gt; object, file descriptor, or array of bytes.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error: .string(limit: &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the &lt;code&gt;standardError&lt;/code&gt; property from the result to access the error message.&lt;/p&gt;&#xA;&lt;h2 id=&#34;supplying-input&#34;&gt;Supplying input&lt;/h2&gt;&#xA;&lt;p&gt;If you need to supply input to a program, add an &lt;code&gt;input&lt;/code&gt; argument to the &lt;code&gt;run&lt;/code&gt; function. You can supply the following kinds of input:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A string&lt;/li&gt;&#xA;&lt;li&gt;A &lt;code&gt;Data&lt;/code&gt; object&lt;/li&gt;&#xA;&lt;li&gt;A file descriptor&lt;/li&gt;&#xA;&lt;li&gt;An array of bytes&lt;/li&gt;&#xA;&lt;li&gt;A data sequence&lt;/li&gt;&#xA;&lt;li&gt;An async data sequence&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-Swift&#34; data-lang=&#34;Swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// content contains the input string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;input: .string(content)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;check-if-a-program-ran-successfully&#34;&gt;Check if a program ran successfully&lt;/h2&gt;&#xA;&lt;p&gt;To see if the program ran successfully, check the &lt;code&gt;terminationStatus&lt;/code&gt; property of the result. The &lt;code&gt;isSuccess&lt;/code&gt; property returns true if the program ran successfully.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; result.terminationStatus.isSuccess {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Success&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Failure&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;a-more-complex-example&#34;&gt;A more complex example&lt;/h2&gt;&#xA;&lt;p&gt;The following function runs the Jujutsu version control system command &lt;code&gt;jj bookmark list&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runListBookmarksCommand&lt;/span&gt;(repoFolder: URL) async -&amp;gt; Result&amp;lt;String, JujutsuError&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; result = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; await run(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      .name(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;jj&amp;#34;&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      arguments: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bookmark&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;list&amp;#34;&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      workingDirectory: FilePath(repoFolder.path(percentEncoded: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;)),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      output: .string(limit: &lt;span style=&#34;color:#ae81ff&#34;&gt;8192&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      error: .string(limit: &lt;span style=&#34;color:#ae81ff&#34;&gt;8192&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; result.terminationStatus.isSuccess {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; .success(result.standardOutput ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; .failure(JujutsuError(message: result.standardError ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error&amp;#34;&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; .failure(JujutsuError(message: error.localizedDescription))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JujutsuError&lt;/span&gt;: Error, Equatable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; message: String = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;related-reading&#34;&gt;Related reading&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/swiftlang/swift-subprocess&#34;&gt;Subprocess GitHub Page&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://blog.jacobstechtavern.com/p/swift-subprocess&#34;&gt;Automate all the things with Swift Subprocess&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://troz.net/post/2025/process-subprocess/&#34;&gt;Moving from Process to Subprocess&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Reducing the Number of .sheet Modifiers in Your SwiftUI Views</title>
      <link>https://swiftdevjournal.com/posts/reducing-sheet-modifiers/</link>
      <pubDate>Mon, 15 Dec 2025 14:07:01 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/reducing-sheet-modifiers/</guid>
      <description>&lt;p&gt;Showing sheets is something most SwiftUI apps do. The most common way to show sheets is to have the following items in a SwiftUI view:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A &lt;code&gt;@State&lt;/code&gt; property in the view that determines whether to show the sheet.&lt;/li&gt;&#xA;&lt;li&gt;Code to set that property to &lt;code&gt;true&lt;/code&gt; from the UI.&lt;/li&gt;&#xA;&lt;li&gt;A &lt;code&gt;.sheet&lt;/code&gt; modifier to show a view in a sheet.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; showSheet = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Button {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  showSheet = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Label(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Add Page&amp;#34;&lt;/span&gt;, systemImage: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plus&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.sheet(isPresented: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;showSheet) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  AddPageView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This way of showing sheets works well if your app shows one or two sheets in a view. If your app shows more sheets in a view, you wind up with a &lt;code&gt;@State&lt;/code&gt; property and a &lt;code&gt;.sheet&lt;/code&gt; modifier for each sheet your app can show. Add enough sheets, and your code becomes a mess.&lt;/p&gt;&#xA;&lt;p&gt;You can reduce the number of Boolean sheet showing properties and &lt;code&gt;.sheet&lt;/code&gt; modifiers by doing the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create an enum for the sheets you want to show.&lt;/li&gt;&#xA;&lt;li&gt;Create a sheet view to show the correct sheet based on the enum you create.&lt;/li&gt;&#xA;&lt;li&gt;Create a focused value to show sheets from menu items.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;creating-an-enum-for-the-sheets&#34;&gt;Creating an enum for the sheets&lt;/h2&gt;&#xA;&lt;p&gt;Create an enum with one case for each sheet your app shows. The enum should conform to the &lt;code&gt;Identifiable&lt;/code&gt; and &lt;code&gt;Hashable&lt;/code&gt; protocols.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Sheet&lt;/span&gt;: Identifiable, Hashable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; addBookmark&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; addChange&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; addRemote&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; editChangeDescription&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; push&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; clone&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; id: &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;creating-a-sheet-view&#34;&gt;Creating a sheet view&lt;/h2&gt;&#xA;&lt;p&gt;Start by creating a SwiftUI view. Add a constant that lets the sheet view know what sheet to know. The type for the constant should be the enum you created. In the &lt;code&gt;body&lt;/code&gt; property, write a &lt;code&gt;switch&lt;/code&gt; statement on the enum to show the correct sheet.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SheetView&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sheet: Sheet&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; sheet {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .addBookmark:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      AddBookmarkView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .addChange:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      AddChangeView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .addRemote:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      AddRemoteView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .editChangeDescription:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      EditDescriptionView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .push:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PushView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .clone:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      CloneView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;creating-a-focused-value&#34;&gt;Creating a focused value&lt;/h2&gt;&#xA;&lt;p&gt;If you want to show sheets from menu items, you must create a focused value that stores the sheet to show. Add an extension to the &lt;code&gt;FocusedValues&lt;/code&gt; struct to create the focused value property. The type of the focused value should be an optional binding to the enum you created.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FocusedValues&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Entry &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; sheetToShow: Binding&amp;lt;Sheet&amp;gt;?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;@Entry&lt;/code&gt; macro supports iOS 18+ and macOS 15+.&lt;/p&gt;&#xA;&lt;p&gt;In the views for your menu items that show sheets, add a &lt;code&gt;@FocusedValue&lt;/code&gt; property so you can set the sheet to show.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@FocusedValue(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.sheetToShow) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; sheet&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In your menu&amp;rsquo;s UI code, set the &lt;code&gt;sheet&lt;/code&gt; property&amp;rsquo;s wrapped value to the enum for the sheet you want to show.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sheet?.wrappedValue = .clone&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Clone&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;showing-a-sheet&#34;&gt;Showing a sheet&lt;/h2&gt;&#xA;&lt;p&gt;To show a sheet from a SwiftUI view, you must do the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Add a &lt;code&gt;@State&lt;/code&gt; property to store the sheet to show.&lt;/li&gt;&#xA;&lt;li&gt;Add a &lt;code&gt;.focusedSceneValue&lt;/code&gt; modifier if you want to show sheets from menus.&lt;/li&gt;&#xA;&lt;li&gt;Set the sheet to show from the view&amp;rsquo;s UI.&lt;/li&gt;&#xA;&lt;li&gt;Add a &lt;code&gt;.sheet&lt;/code&gt; modifier to show the sheet.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;add-state-property&#34;&gt;Add &lt;code&gt;@State&lt;/code&gt; property&lt;/h3&gt;&#xA;&lt;p&gt;Add a &lt;code&gt;@State&lt;/code&gt; property to the SwiftUI view to store the enum for the sheet to show.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; sheetToShow: Sheet? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The type must be an optional value so you can pass the sheet enum to the &lt;code&gt;.sheet&lt;/code&gt; modifier.&lt;/p&gt;&#xA;&lt;h3 id=&#34;add-focusedscenevalue-modifier&#34;&gt;Add &lt;code&gt;.focusedSceneValue&lt;/code&gt; modifier&lt;/h3&gt;&#xA;&lt;p&gt;If you are showing sheets from menus, add a &lt;code&gt;.focusedSceneValue&lt;/code&gt; modifier to the view. The modifier takes two arguments. The name of the first argument must match the name of the variable you added as a &lt;code&gt;FocusedValues&lt;/code&gt; extension. The second argument is a binding to the &lt;code&gt;@State&lt;/code&gt; property you added to the view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.focusedSceneValue(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.sheetToShow, &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;sheetToShow.safeBinding(defaultValue: .addChange))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;safeBinding&lt;/code&gt; function is an extension to convert an optional binding to a non-optional binding. The &lt;code&gt;.focusedSceneValue&lt;/code&gt; modifier cannot accept a binding to an optional value so you must convert the &lt;code&gt;sheetToShow&lt;/code&gt; value to a non-optional value.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Binding&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Convert an optional binding to a non-optional one.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;safeBinding&lt;/span&gt;&amp;lt;T: Sendable&amp;gt;(defaultValue: T) -&amp;gt; Binding&amp;lt;T&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; Value == Optional&amp;lt;T&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Binding&amp;lt;T&amp;gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.wrappedValue ?? defaultValue&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;: { newValue &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.wrappedValue = newValue&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code for the &lt;code&gt;safeBinding&lt;/code&gt; function comes from the Stack Overflow question &lt;a href=&#34;https://stackoverflow.com/questions/68546975/converting-optional-binding-to-non-optional-binding&#34;&gt;Converting optional Binding to non-optional Binding&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;set-the-sheet-to-show&#34;&gt;Set the sheet to show&lt;/h3&gt;&#xA;&lt;p&gt;Set the sheet to show from the view&amp;rsquo;s UI.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sheetToShow = .push&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Label(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Push&amp;#34;&lt;/span&gt;, systemImage:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;square.and.arrow.up&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}).accessibilityLabel(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Push Changes&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;add-sheet-modifier&#34;&gt;Add &lt;code&gt;.sheet&lt;/code&gt; modifier&lt;/h3&gt;&#xA;&lt;p&gt;Finally add a &lt;code&gt;.sheet&lt;/code&gt; modifier to the view and pass a binding to the &lt;code&gt;@State&lt;/code&gt; property as the &lt;code&gt;item&lt;/code&gt; argument. Show the sheet view inside the closure. The argument you pass to the closure contains the enum value that tells the sheet view what sheet to show.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.sheet(item: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;sheetToShow) { sheet &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  SheetView(sheet: sheet)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;related-reading&#34;&gt;Related reading&lt;/h2&gt;&#xA;&lt;p&gt;Azam Sharp wrote the article &lt;a href=&#34;https://azamsharp.com/2024/08/18/global-sheets-pattern-swiftui.html&#34;&gt;Global Sheets Pattern in SwiftUI&lt;/a&gt; that covers how to show global sheets in SwiftUI apps. Azam&amp;rsquo;s article focuses more on iOS and using environment values while this article focuses more on Mac and focused values. His article also shows how to support older OS versions that don&amp;rsquo;t support the &lt;code&gt;@Entry&lt;/code&gt; macro.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Find the SwiftUI Views that Update the Most Using Instruments</title>
      <link>https://swiftdevjournal.com/posts/swiftui-frequent-view-updates/</link>
      <pubDate>Mon, 03 Nov 2025 12:44:02 -0400</pubDate>
      <guid>https://swiftdevjournal.com/posts/swiftui-frequent-view-updates/</guid>
      <description>&lt;p&gt;When profiling a SwiftUI app with Instruments, one thing you want to know is what views update the most. If a view updates more than you expect, you want to know what causes the updates. In this article you will learn how to use the SwiftUI instrument to find the views in your app that update the most and find what triggers view updates.&lt;/p&gt;&#xA;&lt;p&gt;This article uses the new SwiftUI instrument Apple added in Xcode 26. If you are using an earlier version of Xcode, read the following article:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/posts/swiftui-instruments/&#34;&gt;See How Many Times Your SwiftUI Views Redraw Using Instruments&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;profile-your-app&#34;&gt;Profile your app&lt;/h2&gt;&#xA;&lt;p&gt;Take the following steps to profile your app with the SwiftUI instrument:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Go to Xcode.&lt;/li&gt;&#xA;&lt;li&gt;Press Cmd-I or choose Product &amp;gt; Profile to build your project and launch Instruments.&lt;/li&gt;&#xA;&lt;li&gt;Choose SwiftUI from the template list.&lt;/li&gt;&#xA;&lt;li&gt;Click the Choose button.&lt;/li&gt;&#xA;&lt;li&gt;Click the Record button above the sidebar to start profiling.&lt;/li&gt;&#xA;&lt;li&gt;Click the Stop button when you are finished.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;find-the-views-that-update-the-most&#34;&gt;Find the views that update the most&lt;/h2&gt;&#xA;&lt;p&gt;Use the all updates summary to find the views that update the most. Instruments should show the all updates summary when you stop profiling, but if you don&amp;rsquo;t see it in the detail view, press Cmd-1 or choose Summary: All Updates from the jump bar menu.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AllUpdatesSummary.png&#34; alt=&#34;All Updates Summary&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The SwiftUI instrument&amp;rsquo;s all updates summary shows the following statistics for the views in your app:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Number of updates&lt;/li&gt;&#xA;&lt;li&gt;Total update time&lt;/li&gt;&#xA;&lt;li&gt;Shortest update&lt;/li&gt;&#xA;&lt;li&gt;Longest update&lt;/li&gt;&#xA;&lt;li&gt;Average update time&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Take the following steps to find the views that update the most:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Click the disclosure triangle next to the name of your app to see the app&amp;rsquo;s modules.&lt;/li&gt;&#xA;&lt;li&gt;Click the disclosure triangle next to your app&amp;rsquo;s module to see a list of your app’s views.&lt;/li&gt;&#xA;&lt;li&gt;Click the Count column heading to sort the views by update count so you can see what views update the most.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;find-what-causes-a-view-to-update&#34;&gt;Find what causes a view to update&lt;/h2&gt;&#xA;&lt;p&gt;Use the cause and effect graph in the SwiftUI instrument to find the cause of view updates. Take the following steps to show the cause and effect graph for a view:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Move the pointer over a view in the all updates summary.&lt;/li&gt;&#xA;&lt;li&gt;Click the small button that appears next to the name of the view.&lt;/li&gt;&#xA;&lt;li&gt;Choose Show Cause &amp;amp; Effect Graph.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;The cause and effect graph looks similar to the following screenshot:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CauseAndEffectGraph.png&#34; alt=&#34;Cause and Effect Graph&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The graph consists of a collection of nodes with arrows showing the flow of events. Graph nodes for your code are blue. System-defined nodes are gray.&lt;/p&gt;&#xA;&lt;p&gt;Initially the graph is focused on the view you selected from the summary. The nodes to the left of the view show the events that trigger the view update. The nodes to the right of the view show the effects of the view update.&lt;/p&gt;&#xA;&lt;p&gt;To figure out what triggers an update, move left along the graph until you find other blue nodes. The most common cause of view updates is data updates. When the data the view shows changes, the view updates.&lt;/p&gt;&#xA;&lt;p&gt;If you are not seeing any nodes to the left of a particular node, move the pointer over the node to show one or two buttons at the top of the node.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/GraphNodeButtons.png&#34; alt=&#34;Graph node buttons&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Clicking the left button toggles showing and hiding the nodes to the left of the selected node. If no buttons appear, you reached the end of a path.&lt;/p&gt;&#xA;&lt;h2 id=&#34;do-you-want-to-learn-more-about-the-swiftui-instrument&#34;&gt;Do you want to learn more about the SwiftUI instrument?&lt;/h2&gt;&#xA;&lt;p&gt;I wrote a book, &lt;em&gt;Profiling Swift Apps&lt;/em&gt;, that shows you how to use Instruments to find and fix problems in your code. The book has a chapter on using the SwiftUI instrument to find problems in your SwiftUI code. You can learn more about the book and download a sample at the following link:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/instruments-book/&#34;&gt;Profiling Swift Apps page&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Swift-Parsing Library Introduction</title>
      <link>https://swiftdevjournal.com/posts/swift-parsing-intro/</link>
      <pubDate>Mon, 13 Oct 2025 14:54:57 -0400</pubDate>
      <guid>https://swiftdevjournal.com/posts/swift-parsing-intro/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://github.com/pointfreeco/swift-parsing&#34;&gt;swift-parsing library&lt;/a&gt; helps Swift developers parse data. Outside of the library documentation, there isn&amp;rsquo;t a lot of material on using the library so I am sharing what I learned using swift-parsing in an app I&amp;rsquo;m developing.&lt;/p&gt;&#xA;&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;&#xA;&lt;p&gt;The example in this article parses the output of the Jujutsu version control system&amp;rsquo;s &lt;code&gt;jj show&lt;/code&gt; command that shows details of a change. The output of the &lt;code&gt;jj show&lt;/code&gt; command looks similar to the following text:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Commit ID: 73d31d1766b0bc211d22b87f2f911429f3846a61&#xA;Change ID: lyrzonnxolkpxytwwykkqpvvlqmvlxqm&#xA;Bookmarks: trunk@origin&#xA;Author   : Bob Ducca &amp;lt;ducca@example.com&amp;gt; (2025-06-23 18:04:09)&#xA;Committer: Bob Ducca &amp;lt;ducca@example.com&amp;gt; (2025-06-23 18:04:49)&#xA;&#xA;  Add sentence that you have to set a bookmark and push.&#xA;  &#xA;  Add a paragraph so the change description has multiple paragraphs, which is good for unit testing change descriptions.&#xA;&#xA;Modified regular file GitHub.md:&#xA;    ...&#xA;   4    4: &#xA;   5    5: ## Working with Existing GitHub Repo&#xA;   6    6: &#xA;   7    7: In most cases you have an existing GitHub repo. This is what you do.&#xA;        8: &#xA;        9: You have to set a bookmark and call `jj git push`.&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Change&lt;/code&gt; struct stores the change information.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Change&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; changeId: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; author: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; timestamp: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; description: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The rest of the article covers how to use swift-parsing to parse the &lt;code&gt;jj show&lt;/code&gt; command output into the fields of the &lt;code&gt;Change&lt;/code&gt; struct.&lt;/p&gt;&#xA;&lt;h2 id=&#34;parsing-the-change-id&#34;&gt;Parsing the Change ID&lt;/h2&gt;&#xA;&lt;p&gt;The change ID looks like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Change ID: lyrzonnxolkpxytwwykkqpvvlqmvlxqm&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Parsing the change ID involves the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Skip everything through the text &lt;code&gt;Change ID:&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Skip any additional whitespace.&lt;/li&gt;&#xA;&lt;li&gt;Capture everything up to the end of the line.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Use the &lt;code&gt;Skip&lt;/code&gt; parser to skip text. Use the &lt;code&gt;PrefixThrough&lt;/code&gt; parser to go through a certain substring. Use the &lt;code&gt;Whitespace&lt;/code&gt; parser to go through whitespace. The following code performs the first two steps:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Change ID:&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Whitespace()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following code performs the third step:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .map(String.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s show the whole code to create the parser to parse the change ID.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; changeInfo = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Change ID:&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Whitespace()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .map(String.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The parsers in the swift-parsing library return Swift substrings. The &lt;code&gt;.map&lt;/code&gt; line in the code listing converts the parser output into a Swift string.&lt;/p&gt;&#xA;&lt;p&gt;The last thing to do is to get the change ID into the &lt;code&gt;Change&lt;/code&gt; struct. Call the parser&amp;rsquo;s &lt;code&gt;parse&lt;/code&gt; function to get the change ID. Supply the string for the parser to parse. The &lt;code&gt;parse&lt;/code&gt; function can throw errors so you must wrap the call in a &lt;code&gt;do-catch&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  changeId = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; String(changeInfo.parse(commandOutput))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;parsing-the-author&#34;&gt;Parsing the Author&lt;/h2&gt;&#xA;&lt;p&gt;The author looks like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Author   : Bob Ducca &amp;lt;ducca@example.com&amp;gt; (2025-06-23 18:04:09)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Parsing the author requires the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Skip everything through the text &lt;code&gt;Author&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Skip whitespace.&lt;/li&gt;&#xA;&lt;li&gt;Skip the colon.&lt;/li&gt;&#xA;&lt;li&gt;Skip more whitespace.&lt;/li&gt;&#xA;&lt;li&gt;Capture everything up to the &lt;code&gt;&amp;lt;&lt;/code&gt; character, which marks the start of the author email address.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; authorInfo = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Author&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Whitespace()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Whitespace()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Capture everything up to the start of the email address.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; &amp;lt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .map(String.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following code gets the author into the &lt;code&gt;Change&lt;/code&gt; struct:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  author = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; String(authorInfo.parse(commandOutput))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}       }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;parsing-the-timestamp&#34;&gt;Parsing the Timestamp&lt;/h2&gt;&#xA;&lt;p&gt;The timestamp looks like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(2025-06-23 18:04:09)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Parsing the timestamp involves the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Skip everything through the first left parenthesis.&lt;/li&gt;&#xA;&lt;li&gt;Capture everything up to the next right parenthesis.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; timestampInfo = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .map(String.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following code gets the timestamp into the &lt;code&gt;Change&lt;/code&gt; struct:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  timestamp = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; String(timestampInfo.parse(commandOutput))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;parsing-the-description&#34;&gt;Parsing the Description&lt;/h2&gt;&#xA;&lt;p&gt;The change description starts after the first blank line. The description ends with a blank line and one of the following phrases:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Modified regular file&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Added regular file&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Removed regular file&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Start by writing a parser for each possible end of a description.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; modifiedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Modified regular file&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; addedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Added regular file&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; removedFile = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PrefixUpTo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Removed regular file&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the &lt;code&gt;OneOf&lt;/code&gt; parser to capture everything until you reach one of the possible ends of the description. The following code parses the change description:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; descriptionInfo = Parse {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Get to the start of the change description.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PrefixThrough(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Whitespace()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Capture everything up to one of the &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// possible description ends.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  OneOf {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    modifiedFile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addedFile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    removedFile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .map(String.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following code gets the description into the &lt;code&gt;Change&lt;/code&gt; struct:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Remove the indentation at the start of paragraphs &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// and the blank line at the end.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  description = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; String(descriptionInfo.parse(commandOutput))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .trimmingCharacters(&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;: .whitespacesAndNewlines)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;skipping-the-remaining-text&#34;&gt;Skipping the Remaining Text&lt;/h2&gt;&#xA;&lt;p&gt;I ran into a problem when I started parsing change details. The parser returned no matches. Xcode&amp;rsquo;s console printed the following error message:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;error: unexpected input&#xA; --&amp;gt; input:1:10&#xA;1 | Change ID: lyrzonnxolkpxytwwykkqpvvlqmvlxqm&#xA;  |          ^ expected end of input&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I learned that when you have captured everything you want to parse and there&amp;rsquo;s text left to read, you must run the &lt;code&gt;Rest&lt;/code&gt; parser that goes through the rest of the text.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Skip {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Rest()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Find the Slow Spots in Your Code with the CPU Profiler Instrument</title>
      <link>https://swiftdevjournal.com/posts/cpu-profiler/</link>
      <pubDate>Thu, 24 Jul 2025 13:29:07 -0400</pubDate>
      <guid>https://swiftdevjournal.com/posts/cpu-profiler/</guid>
      <description>&lt;p&gt;If you find your Swift app is running slowly, Instruments includes a CPU Profiler instrument to help you find the code causing your app to run slowly. This article shows you how to use the CPU Profiler instrument to find the slow code in your app.&lt;/p&gt;&#xA;&lt;h2 id=&#34;launching-instruments&#34;&gt;Launching Instruments&lt;/h2&gt;&#xA;&lt;p&gt;In Xcode choose Product &amp;gt; Profile or press Cmd-I to build your Xcode project and launch Instruments.&lt;/p&gt;&#xA;&lt;p&gt;When Instruments launches a window opens for you to choose a template to profile your app. Select the CPU Profiler template and click the Choose button. If you are running an older version of Xcode that does not have the CPU Profiler template, select the Time Profiler template.&lt;/p&gt;&#xA;&lt;h2 id=&#34;profiling-your-app&#34;&gt;Profiling Your App&lt;/h2&gt;&#xA;&lt;p&gt;Click the Record button at the top of the trace document window or press Cmd-R to start profiling your app. Run your app.&lt;/p&gt;&#xA;&lt;p&gt;Click the Pause button or press Cmd-Shift-R to pause recording. Click the Stop button or press Cmd-Dot to stop recording.&lt;/p&gt;&#xA;&lt;h2 id=&#34;reading-the-profiling-data&#34;&gt;Reading the Profiling Data&lt;/h2&gt;&#xA;&lt;p&gt;When you stop recording Instruments shows the call tree view.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CPUProfilerCallTreeView.png&#34; alt=&#34;CPU Profiler call tree view&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The call tree view has a listing for each function that executed while profiling.&lt;/p&gt;&#xA;&lt;h3 id=&#34;finding-your-code-in-the-call-tree&#34;&gt;Finding Your Code in the Call Tree&lt;/h3&gt;&#xA;&lt;p&gt;When you first look at the call tree view, you will see it shows lots of functions that you didn&amp;rsquo;t write. How do you find your functions in the call tree view?&lt;/p&gt;&#xA;&lt;p&gt;To find your code in the call tree view, click the Call Tree button at the bottom of the window and click the Hide System Libraries and Invert Call Tree checkboxes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CPUProfilerInvertCallTree.png&#34; alt=&#34;CPU Profiler invert call tree&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Hiding the system library code makes it easier to find your app&amp;rsquo;s functions in the call tree view. Inverting the call tree brings the executed functions to the top of the call tree view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;finding-the-slow-code&#34;&gt;Finding the Slow Code&lt;/h3&gt;&#xA;&lt;p&gt;How do you know which functions are the slow functions?&lt;/p&gt;&#xA;&lt;p&gt;Each function in the call tree view has a Weight value and a Self Weight value. The Weight value tells you how long the function was on the call stack. The Self Weight value tells you how long the function was at the top of the call stack.&lt;/p&gt;&#xA;&lt;p&gt;The Self Weight value is more important. Suppose you have a function A that calls functions X, Y, and Z. The Weight value for A tells you the amount of time your app was in functions A, X, Y, and Z. The Self Weight value for A tells you the amount of time your app was in A. When you&amp;rsquo;re looking for the slow spots in your code, look at functions with a high Self Weight value.&lt;/p&gt;&#xA;&lt;p&gt;Clicking the Self Weight column heading sorts the call tree view listings by their Self Weight value. Sorting by Self Weight brings the slow functions to the top of the call tree view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;viewing-the-slow-code&#34;&gt;Viewing the Slow Code&lt;/h3&gt;&#xA;&lt;p&gt;Double-clicking a function in the call tree view opens the source view, where you can see the lines of code that take the most time in the function. Make sure you double-click a function you wrote. If you double-click a function you didn&amp;rsquo;t write, the source view shows unreadable assembly language code.&lt;/p&gt;&#xA;&lt;h2 id=&#34;do-you-want-to-learn-more-about-instruments&#34;&gt;Do you want to learn more about Instruments?&lt;/h2&gt;&#xA;&lt;p&gt;I wrote a book, &lt;em&gt;Profiling Swift Apps&lt;/em&gt;, that shows you how to use Instruments to find and fix problems in your code. The book will help you make apps that run faster and use less memory. You can learn more about the book and download a sample at the following link:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/instruments-book/&#34;&gt;Profiling Swift Apps page&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Show an Alert from a Menu Item in a SwiftUI Mac App</title>
      <link>https://swiftdevjournal.com/posts/show-swiftui-alert-from-mac-menu/</link>
      <pubDate>Mon, 23 Jun 2025 12:44:56 -0400</pubDate>
      <guid>https://swiftdevjournal.com/posts/show-swiftui-alert-from-mac-menu/</guid>
      <description>&lt;p&gt;SwiftUI provides an &lt;code&gt;.alert&lt;/code&gt; view modifier you can apply to a view to show an alert in your app. If you add the &lt;code&gt;.alert&lt;/code&gt; modifier to a SwiftUI view that is part of a &lt;code&gt;CommandGroup&lt;/code&gt; menu, the alert does not appear. SwiftUI does not support directly showing an alert from a menu in the menu bar because a menu does not have a view for SwiftUI to attach the alert. How do you show the alert?&lt;/p&gt;&#xA;&lt;p&gt;There are two ways to show an alert from a Mac menu item in a SwiftUI app. The first way is to apply the &lt;code&gt;.alert&lt;/code&gt; modifier to the app&amp;rsquo;s content view. The second way is to use AppKit and &lt;code&gt;NSAlert&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;apply-alert-to-the-content-view&#34;&gt;Apply .alert to the Content View&lt;/h2&gt;&#xA;&lt;p&gt;To get the alert to open, apply the &lt;code&gt;.alert&lt;/code&gt; modifier to the content view in the body of the &lt;code&gt;App&lt;/code&gt; struct.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; showAlert = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Scene {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  WindowGroup {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ContentView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      .alert(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Alert message text&amp;#34;&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        isPresented: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;showAlert) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          Button(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;, role: .cancel) { }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the menu item&amp;rsquo;s view, add a binding for showing the alert.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; showAlert: Bool&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set the &lt;code&gt;showAlert&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt; in the menu item code to tell SwiftUI to show the alert.&lt;/p&gt;&#xA;&lt;p&gt;Finally, pass the property from the &lt;code&gt;App&lt;/code&gt; struct to the menu item.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CommandGroup() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  MenuItemView(showAlert: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;showAlert)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Applying the &lt;code&gt;.alert&lt;/code&gt; modifier to the content view works well if your app has only one main window or uses SwiftUI&amp;rsquo;s document architecture. If your app shows multiple windows of the same type using SwiftUI&amp;rsquo;s &lt;code&gt;WindowGroup&lt;/code&gt;, which I wrote about in the &lt;a href=&#34;https://swiftdevjournal.com/posts/swiftui-window-group/&#34;&gt;Open Document-like Windows Using SwiftUI WindowGroup article&lt;/a&gt;, you will notice a problem when you apply the &lt;code&gt;.alert&lt;/code&gt; modifier to the content view.&lt;/p&gt;&#xA;&lt;p&gt;The alert opens once for each open window. If no windows are open, the alert doesn&amp;rsquo;t open.&lt;/p&gt;&#xA;&lt;h2 id=&#34;nsalert&#34;&gt;NSAlert&lt;/h2&gt;&#xA;&lt;p&gt;To open the alert once no matter how many windows are open, use AppKit to show the alert. The AppKit way to show an alert is to create an &lt;code&gt;NSAlert&lt;/code&gt; object, set the alert text, and call the &lt;code&gt;runModal&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; alert = NSAlert()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alert.messageText = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Alert Title&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alert.informativeText = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;More explanatory text&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alert.runModal()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Place the &lt;code&gt;NSAlert&lt;/code&gt; code inside a function and call the function when you want to show the alert.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Open Document-like Windows Using SwiftUI WindowGroup</title>
      <link>https://swiftdevjournal.com/posts/swiftui-window-group/</link>
      <pubDate>Mon, 16 Jun 2025 14:53:48 -0400</pubDate>
      <guid>https://swiftdevjournal.com/posts/swiftui-window-group/</guid>
      <description>&lt;p&gt;Why would you need to open document-like windows without using SwiftUI&amp;rsquo;s document architecture?&lt;/p&gt;&#xA;&lt;p&gt;Suppose you&amp;rsquo;re planning to use SwiftUI to make a Mac git client app like SourceTree or Fork. The app should open a window for each open git repo. SwiftUI&amp;rsquo;s document architecture supports opening a window for each open document, but a git repo can&amp;rsquo;t use most of the document architecture. You&amp;rsquo;re not going to open a blank repo window by pressing Cmd-N, save a repo by pressing Cmd-S, or mark a git repo as being edited. How do you open windows for each repo without using SwiftUI&amp;rsquo;s document architecture?&lt;/p&gt;&#xA;&lt;p&gt;Create a SwiftUI app project and use the &lt;code&gt;WindowGroup&lt;/code&gt; scene type to open additional windows. You must set up the window group to support creating additional windows and write code to open the window.&lt;/p&gt;&#xA;&lt;h2 id=&#34;setting-up-the-window-group&#34;&gt;Setting up the Window Group&lt;/h2&gt;&#xA;&lt;p&gt;The body for the &lt;code&gt;App&lt;/code&gt; struct in a new SwiftUI project has the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Scene {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  WindowGroup {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ContentView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To support creating additional windows, add a &lt;code&gt;for&lt;/code&gt; argument to the &lt;code&gt;WindowGroup&lt;/code&gt; and supply a data type. The data type should be one of your app model&amp;rsquo;s structs or classes that holds the data to show in the window.&lt;/p&gt;&#xA;&lt;p&gt;Add an argument to the closure (after the opening brace) so that each window shows a unique instance of the window group&amp;rsquo;s data type.&lt;/p&gt;&#xA;&lt;p&gt;The following code creates a new window for each open folder in the app and sets the window&amp;rsquo;s title to the folder&amp;rsquo;s display name:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Folder&lt;/span&gt;: Hashable, Codable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; url: URL&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; displayName: String {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    url.path.components(separatedBy: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;).filter{ &lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;$0.isEmpty }.last ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WindowGroup(&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;: Folder.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;folder &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ContentView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .navigationTitle(folder?.displayName ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Window&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In a real app you would have a &lt;code&gt;@Binding&lt;/code&gt; property in the content view and pass the equivalent of &lt;code&gt;$folder&lt;/code&gt; as an argument to the content view.&lt;/p&gt;&#xA;&lt;h2 id=&#34;opening-the-window&#34;&gt;Opening the Window&lt;/h2&gt;&#xA;&lt;p&gt;SwiftUI provides an &lt;code&gt;openWindow&lt;/code&gt; environment property for opening windows in SwiftUI Mac apps. Add an &lt;code&gt;@Environment&lt;/code&gt; property to your SwiftUI view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Environment(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.openWindow) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; openWindow&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create a new instance of the data structure you used as the &lt;code&gt;for&lt;/code&gt; argument to the window group and pass that instance as the value to the &lt;code&gt;openWindow&lt;/code&gt; function. The following code opens a new window for a user-selected folder:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Get the URL from a file importer.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; folder = Folder(url: url)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openWindow(value: folder)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add an Open menu item to the File menu or add a toolbar button to open new windows in your app.&lt;/p&gt;&#xA;&lt;h2 id=&#34;sample-project&#34;&gt;Sample Project&lt;/h2&gt;&#xA;&lt;p&gt;I have &lt;a href=&#34;https://github.com/SwiftDevJournal/MacWindowGroupDemo&#34;&gt;a sample project on GitHub&lt;/a&gt; for you to view and download. Choose File &amp;gt; Open and select a folder on your Mac. The app creates a window and sets its title to the name of the selected folder.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Instruments Flame Graph Introduction</title>
      <link>https://swiftdevjournal.com/posts/instruments-flame-graph-intro/</link>
      <pubDate>Mon, 24 Mar 2025 14:09:38 -0400</pubDate>
      <guid>https://swiftdevjournal.com/posts/instruments-flame-graph-intro/</guid>
      <description>&lt;p&gt;Apple added flame graphs to Instruments in Xcode 16 to let developers visualize call tree statistics. Unfortunately Apple did not add much documentation on using flame graphs. I&amp;rsquo;m writing this article to partially fill the documentation void.&lt;/p&gt;&#xA;&lt;h2 id=&#34;showing-the-flame-graph&#34;&gt;Showing the Flame Graph&lt;/h2&gt;&#xA;&lt;p&gt;You must be in the call tree view to show the flame graph.&lt;/p&gt;&#xA;&lt;p&gt;There are two buttons on the right side above the detail view. Click the rightmost button to show the flame graph.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/FlameGraphButtonArrow.png&#34; alt=&#34;Flame Graph Button&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you don&amp;rsquo;t see the buttons, the instrument does not show flame graphs. Currently only the Time Profiler instrument shows flame graphs. Some time in the future (hopefully soon) all the instruments that have a call tree view will show flame graphs.&lt;/p&gt;&#xA;&lt;h2 id=&#34;reading-the-flame-graph&#34;&gt;Reading the Flame Graph&lt;/h2&gt;&#xA;&lt;p&gt;When you click the button to show the flame graph, the flame graph initially looks similar to the following screenshot:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/FlameGraphAtStart.png&#34; alt=&#34;Flame Graph at Start&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The flame graph consists of stacks of rectangles. Each rectangle represents a function in your app’s call stack. Looking at the screenshot of the flame graph, you will notice that iOS and Mac apps have a lot of functions. Most of the rectangles are so narrow that you can&amp;rsquo;t read the function names.&lt;/p&gt;&#xA;&lt;p&gt;The top of the flame graph shows the function at the bottom of the call stack. This function is most likely the name of your app. Underneath the top rectangle are rectangles for the functions the bottom function called. The stack of rectangles continues downward until you reach the bottom rectangle, which is the function at the top of the call stack.&lt;/p&gt;&#xA;&lt;p&gt;One area where flame graphs excel is telling you the relative amount of time spent in the functions that a function calls. Suppose you have a function A that calls functions B, C, and D. You can tell whether your app spends more time in B, C, or D by the width of the rectangle. The wider the rectangle, the more time the function was on the call stack.&lt;/p&gt;&#xA;&lt;p&gt;If you look at the second row in the flame graph screenshot, you will see the &lt;code&gt;start&lt;/code&gt; function is on the call stack the most, over 70 percent of the time. The &lt;code&gt;start_wqthread&lt;/code&gt; function is on the call stack the second most, around 10 percent. After that are a bunch of other functions whose names you can&amp;rsquo;t read. The names of the functions and the percentages aren&amp;rsquo;t important in this case because they involve code I didn&amp;rsquo;t write. I&amp;rsquo;m using the second row as an example of reading the flame graph. You have to move farther down the flame graph to find code you wrote.&lt;/p&gt;&#xA;&lt;p&gt;The functions that spend the most time on the call stack appear on the left side of the graph.&lt;/p&gt;&#xA;&lt;h2 id=&#34;finding-your-code-in-the-flame-graph&#34;&gt;Finding Your Code in the Flame Graph&lt;/h2&gt;&#xA;&lt;p&gt;Functions you wrote have a blue rectangle. You must scroll down the flame graph to find your code because the top of the graph has blue rectangles for functions in your app that you didn&amp;rsquo;t write, such as &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The easiest way to find your code is to hide functions in system libraries from the flame graph. Click the Call Tree button at the bottom of the window and select the Hide System Libraries checkbox.&lt;/p&gt;&#xA;&lt;h2 id=&#34;navigating-the-flame-graph&#34;&gt;Navigating the Flame Graph&lt;/h2&gt;&#xA;&lt;p&gt;Click a rectangle in the flame graph to select it. After selecting a rectangle, use the arrow keys to navigate the flame graph.&lt;/p&gt;&#xA;&lt;h2 id=&#34;zooming-the-flame-graph&#34;&gt;Zooming the Flame Graph&lt;/h2&gt;&#xA;&lt;p&gt;The number of functions in iOS and Mac apps makes it tough to read the function names for most of the flame graph rectangles. How do you zoom the flame graph so you can read those function names?&lt;/p&gt;&#xA;&lt;p&gt;Create a zoom area. Start by clicking in the flame graph to establish the start of the zoom area. Hold down the Option key, scroll, and release the mouse button to set the zoom area. You can also zoom with a trackpad gesture, but I don&amp;rsquo;t have a trackpad to test this.&lt;/p&gt;&#xA;&lt;p&gt;Combine creating a zoom area and hiding system libraries to make your function names readable in the flame graph.&lt;/p&gt;&#xA;&lt;p&gt;To zoom out, hold down the Option key and click in the graph. Scroll to the top of the flame graph and option-click to zoom out completely.&lt;/p&gt;&#xA;&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;&#xA;&lt;p&gt;The following list has the most important things to remember when reading Instruments flame graphs:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Rectangle width indicates the percentage of time the function was on the call stack.&lt;/li&gt;&#xA;&lt;li&gt;The functions that spend the most time on the call stack appear on the left side of the graph.&lt;/li&gt;&#xA;&lt;li&gt;Functions in your app have blue rectangles.&lt;/li&gt;&#xA;&lt;li&gt;Hide system libraries to focus on your code. Click the Call Tree button at the bottom of the window to hide system libraries.&lt;/li&gt;&#xA;&lt;li&gt;Option-scroll to zoom the flame graph to read function names.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;acknowledgments&#34;&gt;Acknowledgments&lt;/h2&gt;&#xA;&lt;p&gt;Thanks to James Dempsey and Philippe Casgrain for the information on zooming the flame graph.&lt;/p&gt;&#xA;&lt;h2 id=&#34;do-you-want-to-learn-more-about-instruments&#34;&gt;Do you want to learn more about Instruments?&lt;/h2&gt;&#xA;&lt;p&gt;I wrote a book, &lt;em&gt;Profiling Swift Apps&lt;/em&gt;, that shows you how to use Instruments to find and fix problems in your code. The book will help you make apps that run faster and use less memory. You can learn more about the book and download a sample at the following link:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/instruments-book/&#34;&gt;Profiling Swift Apps page&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Using Jujutsu Version Control in Xcode Projects</title>
      <link>https://swiftdevjournal.com/posts/jujutsu-xcode/</link>
      <pubDate>Mon, 17 Mar 2025 13:31:16 -0400</pubDate>
      <guid>https://swiftdevjournal.com/posts/jujutsu-xcode/</guid>
      <description>&lt;p&gt;Last update: January 2026&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/jj-vcs/jj&#34;&gt;Jujutsu&lt;/a&gt;, also known as jj, is a version control system that is growing in popularity with developers. One reason for its popularity is that it works with git repositories and services like GitHub.&lt;/p&gt;&#xA;&lt;p&gt;In this article I share what I learned about using Jujutsu in Xcode projects and putting Jujutsu repos on GitHub. The article has two main sections: one on adding Jujutsu to an Xcode project with an existing git repo and one on adding Jujutsu to a project with no git repo.&lt;/p&gt;&#xA;&lt;p&gt;Disclaimer: I am learning Jujutsu. I am not an expert on it.&lt;/p&gt;&#xA;&lt;p&gt;I refer to Jujutsu in this article using both Jujutsu and jj.&lt;/p&gt;&#xA;&lt;h2 id=&#34;adding-jujutsu-to-an-xcode-project-with-a-git-repo&#34;&gt;Adding Jujutsu to an Xcode Project with a Git Repo&lt;/h2&gt;&#xA;&lt;p&gt;To add Jujutsu support to an Xcode project, you must create a jj repository for the project from the Terminal app. In the Terminal navigate to the directory above your Xcode project&amp;rsquo;s folder. If you are inexperienced with the Terminal, go to the directory above your project folder in the Finder, right-click, and choose Services &amp;gt; New Terminal at Folder. A Terminal window will open with the current directory being the directory above the project folder.&lt;/p&gt;&#xA;&lt;p&gt;Run the following command to create a jj repo:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;jj git init --colocate RepoName&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where &lt;code&gt;RepoName&lt;/code&gt; is the name you give to the repo.&lt;/p&gt;&#xA;&lt;p&gt;Now your Xcode project has two version control repos: a git repo and a jj repo. You can see this for yourself in the Finder by pressing Cmd-Shift-Dot. There will be a &lt;code&gt;.git&lt;/code&gt; folder and a &lt;code&gt;.jj&lt;/code&gt; folder inside your project folder.&lt;/p&gt;&#xA;&lt;p&gt;Using the &lt;code&gt;--colocate&lt;/code&gt; option tells Jujutsu that the git and jj repos share the same working copy. Xcode will continue to track the changes in your project. If you commit changes using Xcode or another git app like SourceTree, the commits appear in both the git and jj repos.&lt;/p&gt;&#xA;&lt;h3 id=&#34;putting-the-jujutsu-repo-on-github&#34;&gt;Putting the Jujutsu Repo on GitHub&lt;/h3&gt;&#xA;&lt;p&gt;If you want your Jujutsu repo on GitHub and have not created a remote GitHub branch for the Xcode project, do so from the Source Control navigator, which you can access by pressing Cmd-2. The following article has detailed instructions on putting an Xcode project on GitHub:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/putting-your-xcode-project-on-github-bitbucket-or-gitlab/&#34;&gt;Putting Your Xcode Project on GitHub, Bitbucket, or GitLab&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;You must push the jj repo to GitHub. You have to do this from the Terminal. Go to your project folder in the Terminal.&lt;/p&gt;&#xA;&lt;p&gt;Run the following commands to push the local jj repo to GitHub:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;jj describe -m &amp;#34;Initial push to GitHub&amp;#34;&#xA;&#xA;jj bookmark set trunk --allow-backwards -r @-&#xA;&#xA;jj git push --allow-new -b trunk&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first command creates a description for a commit. I got an error when I pushed to GitHub without creating a description.&lt;/p&gt;&#xA;&lt;p&gt;The second command creates a &lt;code&gt;trunk&lt;/code&gt; branch for you to push to GitHub. The &lt;code&gt;--allow-backwards&lt;/code&gt; option lets you move the bookmark backwards or sideways, which you need the first time you set a bookmark.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;-r&lt;/code&gt; option specifies the change (commit) where the bookmark should point. In most cases you should point the bookmark to the most recent change you made. Run the &lt;code&gt;jj status&lt;/code&gt; command to check if the working copy is empty.&lt;/p&gt;&#xA;&lt;p&gt;If the working copy is not empty, point the bookmark to the working copy by passing &lt;code&gt;@&lt;/code&gt; as the change ID. If the working copy is empty, point the bookmark to the working copy&amp;rsquo;s parent commit by passing &lt;code&gt;@-&lt;/code&gt; as the change ID.&lt;/p&gt;&#xA;&lt;p&gt;The final command pushes the local jj repo to the &lt;code&gt;trunk&lt;/code&gt; branch on GitHub. Supply the &lt;code&gt;--allow-new&lt;/code&gt; and &lt;code&gt;-b&lt;/code&gt; options along with the name of the bookmark. The &lt;code&gt;--allow-new&lt;/code&gt; option allows creating new bookmarks, which you need to do the first time you push.&lt;/p&gt;&#xA;&lt;p&gt;If you don&amp;rsquo;t supply the &lt;code&gt;-b&lt;/code&gt; argument, Jujutsu issues a warning about the working copy commit becoming immutable.&lt;/p&gt;&#xA;&lt;p&gt;The GitHub repo should have a &lt;code&gt;main&lt;/code&gt; branch that contains the project&amp;rsquo;s git repo and a &lt;code&gt;trunk&lt;/code&gt; branch that contains the jj repo.&lt;/p&gt;&#xA;&lt;h2 id=&#34;adding-jujutsu-to-an-xcode-project-with-no-git-repo&#34;&gt;Adding Jujutsu to an Xcode Project with no Git Repo&lt;/h2&gt;&#xA;&lt;p&gt;To add Jujutsu support to your Xcode project, you must create a jj repo for the project. Go to your project folder in the Terminal and run the following command:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;jj git init&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Running the command creates a &lt;code&gt;.jj&lt;/code&gt; folder in your project folder. You can see this for yourself in the Finder by pressing Cmd-Shift-Dot.&lt;/p&gt;&#xA;&lt;p&gt;Xcode will not show the changes in your code because the project has a jj repo and no git repo. If you want Xcode to show the changes in your code, you must create a git repo. In Xcode choose Integrate &amp;gt; New Git Repository to add a git repo to your project.&lt;/p&gt;&#xA;&lt;h3 id=&#34;putting-the-jujutsu-repo-on-github-1&#34;&gt;Putting the Jujutsu Repo on GitHub&lt;/h3&gt;&#xA;&lt;p&gt;You must create a repository in GitHub and push your local jj repo to that repo. When you create the repo in GitHub, GitHub provides instructions on how to push an existing repo. The commands in those instructions provide a guide on what you need to run to push your local jj repo to GitHub.&lt;/p&gt;&#xA;&lt;p&gt;Run the following commands to put your local jj repo on GitHub:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;jj git remote add origin https://github.com/GitHubAccount/RepoName.git&#xA;&#xA;jj describe -m &amp;#34;Initial push to GitHub&amp;#34;&#xA;&#xA;jj bookmark set trunk --allow-backwards -r @-&#xA;&#xA;jj git push --allow-new -b trunk&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first command adds a remote branch to your local repo. The branch contains the repo you created on GitHub. Replace &lt;code&gt;GitHubAccount&lt;/code&gt; with your GitHub username, and replace &lt;code&gt;RepoName&lt;/code&gt; with your repo name.&lt;/p&gt;&#xA;&lt;p&gt;The second command creates a description for a commit. I got an error when I pushed to GitHub without creating a description.&lt;/p&gt;&#xA;&lt;p&gt;The third command creates a &lt;code&gt;trunk&lt;/code&gt; branch for you to push to GitHub. The &lt;code&gt;--allow-backwards&lt;/code&gt; option lets you move the bookmark backwards or sideways, which you need the first time you set a bookmark.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;-r&lt;/code&gt; option specifies the change (commit) where the bookmark should point. In most cases you should point the bookmark to the most recent change you made. Run the &lt;code&gt;jj status&lt;/code&gt; command to check if the working copy is empty.&lt;/p&gt;&#xA;&lt;p&gt;If the working copy is not empty, point the bookmark to the working copy by passing &lt;code&gt;@&lt;/code&gt; as the change ID. If the working copy is empty, point the bookmark to the working copy&amp;rsquo;s parent commit by passing &lt;code&gt;@-&lt;/code&gt; as the change ID.&lt;/p&gt;&#xA;&lt;p&gt;The final command pushes the local jj repo to the &lt;code&gt;trunk&lt;/code&gt; branch on GitHub. Supply the &lt;code&gt;--allow-new&lt;/code&gt; and &lt;code&gt;-b&lt;/code&gt; options along with the name of the bookmark. The &lt;code&gt;--allow-new&lt;/code&gt; option allows creating new bookmarks, which you need to do the first time you push.&lt;/p&gt;&#xA;&lt;p&gt;If you don&amp;rsquo;t supply the &lt;code&gt;-b&lt;/code&gt; argument, Jujutsu issues a warning about the working copy commit becoming immutable.&lt;/p&gt;&#xA;&lt;h2 id=&#34;further-reading&#34;&gt;Further Reading&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/jj-vcs/jj&#34;&gt;Jujutsu GitHub page&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.jj-vcs.dev&#34;&gt;Jujutsu Docs&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://steveklabnik.github.io/jujutsu-tutorial/introduction/introduction.html&#34;&gt;Steve&amp;rsquo;s Jujutsu Tutorial&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;looking-for-a-jujutsu-gui-client&#34;&gt;Looking for a Jujutsu GUI Client?&lt;/h2&gt;&#xA;&lt;p&gt;If so, I&amp;rsquo;m developing &lt;a href=&#34;https://checksimsoftware.com/jjewel&#34;&gt;Jjewel&lt;/a&gt;, a native Mac app that provides a GUI for Jujutsu. Use Jjewel to perform the most common version control tasks and spend less time entering Terminal commands.&lt;/p&gt;&#xA;&lt;p&gt;Go to the &lt;a href=&#34;https://checksimsoftware.com/jjewel&#34;&gt;Jjewel site&lt;/a&gt; to learn more about the app and download it.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>See How Many Times Your SwiftUI Views Redraw Using Instruments</title>
      <link>https://swiftdevjournal.com/posts/swiftui-instruments/</link>
      <pubDate>Mon, 10 Mar 2025 12:07:02 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/swiftui-instruments/</guid>
      <description>&lt;p&gt;If you run into a performance problem in your SwiftUI app, the cause could be your app&amp;rsquo;s views redrawing too often. Apple provides instruments in the Instruments app that let you see how many times SwiftUI draws your app&amp;rsquo;s views and the view properties that trigger redraws. This article shows how to use those instruments.&lt;/p&gt;&#xA;&lt;h2 id=&#34;profile-your-app&#34;&gt;Profile Your App&lt;/h2&gt;&#xA;&lt;p&gt;Take the following steps to profile your app with the SwiftUI instruments:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Go to Xcode.&lt;/li&gt;&#xA;&lt;li&gt;Press Cmd-I or choose Product &amp;gt; Profile to build your project and launch Instruments.&lt;/li&gt;&#xA;&lt;li&gt;Choose SwiftUI from the template list.&lt;/li&gt;&#xA;&lt;li&gt;Click the Choose button.&lt;/li&gt;&#xA;&lt;li&gt;Click the Record button above the sidebar to start profiling.&lt;/li&gt;&#xA;&lt;li&gt;Click the Stop button when you are finished.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;The SwiftUI template has the following instruments:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;View Body&lt;/li&gt;&#xA;&lt;li&gt;View Properties&lt;/li&gt;&#xA;&lt;li&gt;Core Animation Commits&lt;/li&gt;&#xA;&lt;li&gt;Time Profiler&lt;/li&gt;&#xA;&lt;li&gt;Hangs&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I cover the View Body and View Properties instruments in this article. Read the following article to learn more about the Time Profiler instrument:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/finding-the-slow-spots-in-your-code-with-the-time-profiler-instrument/&#34;&gt;Finding the Slow Spots in Your Code with the Time Profiler Instrument&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;see-the-number-of-view-redraws&#34;&gt;See the Number of View Redraws&lt;/h2&gt;&#xA;&lt;p&gt;Use the View Body instrument to see statistics about the redraws of the SwiftUI views in your app. The View Body instrument table has the following columns of data:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Count&lt;/li&gt;&#xA;&lt;li&gt;Total Duration&lt;/li&gt;&#xA;&lt;li&gt;Minimum Duration&lt;/li&gt;&#xA;&lt;li&gt;Average Duration&lt;/li&gt;&#xA;&lt;li&gt;Maximum Duration&lt;/li&gt;&#xA;&lt;li&gt;Standard Deviation Duration&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The most important columns are Count, Total Duration, and Average Duration. The Count column tells you how many times SwiftUI drew the view. The Total Duration column tells you the total time of those draws. The Average Duration column tells you the average time of each draw.&lt;/p&gt;&#xA;&lt;p&gt;The View Body instrument table has at least two rows: one for SwiftUI and one for your app. Start by looking at the statistics for your app. You will see the total number of times SwiftUI drew your app&amp;rsquo;s views.&lt;/p&gt;&#xA;&lt;p&gt;To see what views were drawn the most, click the disclosure triangle next to your app. There will be a row for each view in your SwiftUI app.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ViewBodyInstrumentAppViewsStats.png&#34; alt=&#34;App view stats&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The views that were drawn the most should appear at the top. If you don&amp;rsquo;t see the views that were drawn the most, click the Count table header to sort the views by count.&lt;/p&gt;&#xA;&lt;h1 id=&#34;see-the-properties-that-trigger-redraws&#34;&gt;See the Properties that Trigger Redraws&lt;/h1&gt;&#xA;&lt;p&gt;If you find one of your views is being redrawn often, you want to figure out what is causing the view to redraw so much. How do you find the cause of redraws?&lt;/p&gt;&#xA;&lt;p&gt;SwiftUI views redraw when the data bound to the views changes. Use the View Properties instrument to see the properties (variables) that change the most. Anything in your code that uses property wrappers like &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@Binding&lt;/code&gt; will appear in this instrument.&lt;/p&gt;&#xA;&lt;p&gt;When you select the View Properties instrument, you will see a long list of properties with their current values. You can get more useful information from the summary. Press Cmd-2 or choose Summary from the jump bar to see the summary.&lt;/p&gt;&#xA;&lt;p&gt;The summary looks similar to the summary for the View Body instrument. There are rows for SwiftUI and your app. There is one column that tells you the number of updates.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ViewPropertyInstrumentAppStats.png&#34; alt=&#34;View property app stats&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Where the View Properties instrument differs is it has levels you can drill down by clicking disclosure triangles. The View Properties instrument has the following levels:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;View type&lt;/li&gt;&#xA;&lt;li&gt;Property type&lt;/li&gt;&#xA;&lt;li&gt;Property value&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The view types for your app are your app&amp;rsquo;s views. They should be the same as the views in the View Body instrument.&lt;/p&gt;&#xA;&lt;p&gt;The property types are the data types for the properties in your SwiftUI views. An example of a property type in a SwiftUI view is &lt;code&gt;Binding&amp;lt;String&amp;gt;&lt;/code&gt;, which is a binding to a string. The instrument shows the data types, not the names of your variables.&lt;/p&gt;&#xA;&lt;p&gt;The property values show the different values the property had during profiling. A Boolean property will show the number of times it was set to true and set to false.&lt;/p&gt;&#xA;&lt;p&gt;You are noticing there&amp;rsquo;s a lot of disclosure triangle clicking when looking at view properties. Option-clicking a disclosure triangle will expand the list to show all the levels so you don&amp;rsquo;t have to click as much. Option-clicking again will contract the list.&lt;/p&gt;&#xA;&lt;h2 id=&#34;do-you-want-to-learn-more-about-instruments&#34;&gt;Do you want to learn more about Instruments?&lt;/h2&gt;&#xA;&lt;p&gt;I wrote a book, &lt;em&gt;Profiling Swift Apps&lt;/em&gt;, that shows you how to use Instruments to find and fix problems in your code. The book will help you make apps that run faster and use less memory. You can learn more about the book and download a sample at the following link:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/instruments-book/&#34;&gt;Profiling Swift Apps page&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Set the Sidebar Initial Width in SwiftUI Navigation Split View</title>
      <link>https://swiftdevjournal.com/posts/set-sidebar-initial-width-in-split-view/</link>
      <pubDate>Mon, 24 Feb 2025 14:22:06 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/set-sidebar-initial-width-in-split-view/</guid>
      <description>&lt;p&gt;When you use a navigation split view in a SwiftUI Mac app, you normally have a sidebar in the left column. You want to give the sidebar an initial width that is wide enough to show the sidebar contents while letting people resize the sidebar. How do you provide the initial width?&lt;/p&gt;&#xA;&lt;p&gt;Add the &lt;code&gt;.navigationSplitViewColumnWidth&lt;/code&gt; modifier to the sidebar view and supply the initial width you want. The following code sets the sidebar width to 192 points:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NavigationSplitView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;Sidebar()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;.navigationSplitViewColumnWidth(ideal: &lt;span style=&#34;color:#ae81ff&#34;&gt;192&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} detail: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#x9;DetailView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Downloading Older Versions of Xcode</title>
      <link>https://swiftdevjournal.com/posts/downloading-older-xcode-versions/</link>
      <pubDate>Tue, 28 Jan 2025 13:50:14 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/downloading-older-xcode-versions/</guid>
      <description>&lt;p&gt;Those of you running older versions of macOS will run into problems if you try to install Xcode from the Mac App Store. The Mac App Store has only the most recent version of Xcode. The most recent version of Xcode usually requires the latest version of macOS. How do you download older versions of Xcode?&lt;/p&gt;&#xA;&lt;h2 id=&#34;apples-xcode-downloads-page&#34;&gt;Apple&amp;rsquo;s Xcode Downloads Page&lt;/h2&gt;&#xA;&lt;p&gt;Apple has an &lt;a href=&#34;https://developer.apple.com/xcode/resources/&#34;&gt;Xcode Downloads page&lt;/a&gt; where you can download older Xcode versions.&lt;/p&gt;&#xA;&lt;h2 id=&#34;xcode-releases&#34;&gt;Xcode Releases&lt;/h2&gt;&#xA;&lt;p&gt;A faster way to find Apple&amp;rsquo;s download links is to go to &lt;a href=&#34;https://xcodereleases.com/&#34;&gt;Xcode Releases&lt;/a&gt;. The Xcode Releases site has Apple&amp;rsquo;s download links for every version of Xcode. Xcode Releases also lists the minimum version of macOS required for each Xcode version.&lt;/p&gt;&#xA;&lt;h2 id=&#34;xcodes-app&#34;&gt;Xcodes App&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/XcodesOrg/XcodesApp&#34;&gt;The Xcodes app&lt;/a&gt; provides another way to install older versions of Xcode. I have not use Xcodes, but lots of developers recommend it for downloading and installing Xcode.&lt;/p&gt;&#xA;&lt;h2 id=&#34;latest-xcode-versions-for-older-macos-versions&#34;&gt;Latest Xcode Versions for Older macOS Versions&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Xcode 16.2 is the latest version for macOS 14.&lt;/li&gt;&#xA;&lt;li&gt;Xcode 15.3 is the latest version for macOS 13.&lt;/li&gt;&#xA;&lt;li&gt;Xcode 14.2 is the latest version for macOS 12.&lt;/li&gt;&#xA;&lt;li&gt;Xcode 13.2.1 is the latest version for macOS 11.&lt;/li&gt;&#xA;&lt;li&gt;Xcode 12.4 is the latest version for macOS 10.15.&lt;/li&gt;&#xA;&lt;li&gt;Xcode 11.3.1 is the latest version for macOS 10.14.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;You can see the pattern for earlier macOS versions.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Troubleshooting File Loading Problems in Swift Apps</title>
      <link>https://swiftdevjournal.com/posts/troubleshooting-file-loading/</link>
      <pubDate>Mon, 25 Nov 2024 14:08:58 -0500</pubDate>
      <guid>https://swiftdevjournal.com/posts/troubleshooting-file-loading/</guid>
      <description>&lt;p&gt;A problem that people learning to develop iOS and Mac apps run into is being unable to load files they include in their app, such as image files, sound files, and text files. This is a frustrating problem because your code is usually not the source of the problem. The problem is the operating system cannot find the file in the app bundle.&lt;/p&gt;&#xA;&lt;p&gt;This article has tips on fixing file loading problems in your app.&lt;/p&gt;&#xA;&lt;h2 id=&#34;where-do-swift-gui-apps-look-for-files&#34;&gt;Where do Swift GUI apps look for files?&lt;/h2&gt;&#xA;&lt;p&gt;Swift apps look for files in the Resources folder of your app bundle. When you write code to load a file, such as the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sampleData = bundle.url(forResource: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SampleData&amp;#34;&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    withExtension: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The operating system looks in the Resources folder. If it does not find the file, the function returns nil. The operating system does not search the entire app bundle, just the Resources folder.&lt;/p&gt;&#xA;&lt;p&gt;It is very important that the files your app loads are in the app bundle&amp;rsquo;s Resources folder. If the files are not in the Resources folder, your app will not be able to load them.&lt;/p&gt;&#xA;&lt;h2 id=&#34;make-sure-the-files-are-in-the-app-bundles-resources-folder&#34;&gt;Make sure the files are in the app bundle&amp;rsquo;s Resources folder&lt;/h2&gt;&#xA;&lt;p&gt;If you run into problems with loading files, make sure the files you want to load are going to be copied to the app bundle&amp;rsquo;s Resources folder when Xcode builds your project. To make sure the files will be copied to the Resources folder, make sure they are in the app target&amp;rsquo;s Copy Bundle Resources build phase. The files must be part of this build phase to get copied to the app bundle.&lt;/p&gt;&#xA;&lt;p&gt;Take the following steps to see the files in the Copy Bundle Resources build phase:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Open the project editor by selecting the project file from the left side of the project window.&lt;/li&gt;&#xA;&lt;li&gt;Select the app target from the target list on the left side of the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Click the Build Phase button at the top of the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Click the disclosure triangle next to the Copy Bundle Resources build phase.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CopyBundleResources.png&#34; alt=&#34;Screenshot of Copy Bundle Resources build phase files&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If your files are not in the Copy Bundle Resources build phase, click the Add button below the list of files to open a sheet where you can choose the files to add to the build phase.&lt;/p&gt;&#xA;&lt;h2 id=&#34;make-sure-the-file-names-match-exactly&#34;&gt;Make sure the file names match exactly&lt;/h2&gt;&#xA;&lt;p&gt;The code example earlier in this article,&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sampleData = bundle.url(forResource: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SampleData&amp;#34;&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    withExtension: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looks for a file with the name &lt;code&gt;SampleData.json&lt;/code&gt; in the Resources folder. The &lt;code&gt;Bundle&lt;/code&gt; class file search is case sensitive. If the name of the file in the app bundle is &lt;code&gt;sampledata.json&lt;/code&gt;, the code example above won&amp;rsquo;t find the file because the file names don&amp;rsquo;t match exactly.&lt;/p&gt;&#xA;&lt;p&gt;Also make sure you didn&amp;rsquo;t misspell the name of the file in your code. It&amp;rsquo;s easy to make a small typo that causes file loading problems.&lt;/p&gt;&#xA;&lt;h2 id=&#34;dont-include-the-dot-when-giving-the-file-extension&#34;&gt;Don&amp;rsquo;t include the dot when giving the file extension&lt;/h2&gt;&#xA;&lt;p&gt;The Bundle class&amp;rsquo;s &lt;code&gt;url&lt;/code&gt; function takes a file extension as an argument. An easy mistake to make is to include the dot in the extension, such as the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sampleData = bundle.url(forResource: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SampleData&amp;#34;&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    withExtension: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.json&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this code, the operating system is going to look for a file named &lt;code&gt;SampleData..json&lt;/code&gt;, which most likely does not exist.&lt;/p&gt;&#xA;&lt;p&gt;Do not include the dot when specifying file extensions.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sampleData = bundle.url(forResource: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SampleData&amp;#34;&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    withExtension: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;using-folders-of-files-in-your-app&#34;&gt;Using folders of files in your app&lt;/h2&gt;&#xA;&lt;p&gt;If you include a lot of files in your app, you may place them in separate folders to make them easier to organize. You might have a folder for data files and a folder for audio files.&lt;/p&gt;&#xA;&lt;p&gt;Suppose you have a separate folder for your JSON files. If you use the code I have used throughout this article to load a JSON file,&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sampleData = bundle.url(forResource: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SampleData&amp;#34;&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    withExtension: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;url&lt;/code&gt; function returns nil because the JSON files are in a folder inside the Resources folder. The function looks in the Resources folder, doesn&amp;rsquo;t find the JSON file in that folder, and returns nil.&lt;/p&gt;&#xA;&lt;p&gt;The fix is to add a &lt;code&gt;subdirectory&lt;/code&gt; argument to the &lt;code&gt;url&lt;/code&gt; function call and specify the name of the folder where the file is located.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sampleData = bundle.url(forResource: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SampleData&amp;#34;&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    withExtension: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json&amp;#34;&lt;/span&gt;, subdirectory: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JSON&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>SwiftUI Tip: Avoid Nesting ObservableObjects</title>
      <link>https://swiftdevjournal.com/swiftui-tip-avoid-nesting-observableobjects/</link>
      <pubDate>Mon, 26 Aug 2024 23:02:12 +0000</pubDate>
      <guid>https://swiftdevjournal.com/swiftui-tip-avoid-nesting-observableobjects/</guid>
      <description>&lt;p&gt;A problem many SwiftUI developers have is their views not updating when the data changes. A common reason for this problem is having nested ObservableObjects in their code.&lt;/p&gt;&#xA;&lt;p&gt;In this article you will learn what a nested ObservableObject is, why nested ObservableObjects cause problems, and how you can get your views to update correctly.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatisanestedobservableobject&#34;&gt;What is a Nested ObservableObject?&lt;/h3&gt;&#xA;&lt;p&gt;A nested ObservableObject occurs when you have a class that conforms to &lt;code&gt;ObservableObject&lt;/code&gt; and has a property whose class also conforms to &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Let’s look at an example of a nested ObservableObject. Suppose you have an issue tracking app. The data model for the app includes projects and issues. Each project can have multiple issues.&lt;/p&gt;&#xA;&lt;p&gt;If you make &lt;code&gt;Project&lt;/code&gt; a class, have it conform to &lt;code&gt;ObservableObject&lt;/code&gt;, and give it a list of issues,&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Project&lt;/span&gt;: ObservableObject {   &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Published &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; issues: [Issue]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the &lt;code&gt;Issue&lt;/code&gt; class conforms to &lt;code&gt;ObservableObject&lt;/code&gt;,&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Issue&lt;/span&gt;: ObservableObject {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You have a nested ObservableObject. &lt;code&gt;Issue&lt;/code&gt; is nested inside &lt;code&gt;Project&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatswrongwithnestedobservableobjects&#34;&gt;What’s Wrong with Nested ObservableObjects?&lt;/h3&gt;&#xA;&lt;p&gt;Why do nested ObservableObjects cause problems? When a change occurs in the inner object, SwiftUI does not automatically report the change to the outer object. This means the view for the outer object will not update when the data in the inner object changes.&lt;/p&gt;&#xA;&lt;p&gt;In the issue tracking app example, the project does not get notified of any changes to its issues. When an issue changes, the project’s view will not update to reflect the changes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;fixingtheproblem&#34;&gt;Fixing the Problem&lt;/h3&gt;&#xA;&lt;p&gt;At this point you’re wondering what you have to do to fix the problem and get your views to update correctly. The following techniques can fix the problem:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Use structs instead of classes for your data models.&lt;/li&gt;&#xA;&lt;li&gt;Use the Observation framework.&lt;/li&gt;&#xA;&lt;li&gt;Manually send a message when there is a change in the inner object.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;usestructsinsteadofclasses&#34;&gt;Use Structs Instead of Classes&lt;/h4&gt;&#xA;&lt;p&gt;Using structs for your data models can be the easiest fix. Structs do not use the &lt;code&gt;ObservableObject&lt;/code&gt; protocol so you won’t get nested ObservableObjects. In the issue tracker example, making &lt;code&gt;Project&lt;/code&gt; or &lt;code&gt;Issue&lt;/code&gt; a struct will eliminate the nested ObservableObject.&lt;/p&gt;&#xA;&lt;p&gt;But you might find that parts of your app’s data model must be classes. When I was developing &lt;a href=&#34;https://www.checksimsoftware.com/bartleby/&#34;&gt;Bartleby&lt;/a&gt;, I initially tried using a struct for book chapters, but the chapter text would not save when I switched chapters. The only way to get the chapter text to save was to make &lt;code&gt;Chapter&lt;/code&gt; a class. You may have a similar situation in your app.&lt;/p&gt;&#xA;&lt;p&gt;Remember you don’t have to change every class in your app to a struct. Make sure you don’t have one class nested inside another class.&lt;/p&gt;&#xA;&lt;h4 id=&#34;usetheobservationframework&#34;&gt;Use the Observation Framework&lt;/h4&gt;&#xA;&lt;p&gt;Apple added the &lt;a href=&#34;https://developer.apple.com/documentation/Observation&#34;&gt;Observation framework&lt;/a&gt; in iOS 17 and macOS 14. If you use the Observation framework for your data and to pass data to views, you will fix the problem.&lt;/p&gt;&#xA;&lt;p&gt;The downside of using Observation is you can’t use it in earlier iOS and macOS versions. If you need to support iOS 16 or earlier in your app, you can’t use the Observation framework.&lt;/p&gt;&#xA;&lt;h4 id=&#34;manualchanges&#34;&gt;Manual Changes&lt;/h4&gt;&#xA;&lt;p&gt;If you can’t use structs for your data model, can’t avoid nesting ObservableObjects, and can’t use the Observation framework, you have one more workaround. Manually sending a message when the data changes.&lt;/p&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;objectWillChange.send&lt;/code&gt; function to manually send a message when the data changes. The function takes no arguments.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>macOS by Tutorials Book Review</title>
      <link>https://swiftdevjournal.com/macos-by-tutorials-book-review/</link>
      <pubDate>Mon, 05 Aug 2024 17:33:14 +0000</pubDate>
      <guid>https://swiftdevjournal.com/macos-by-tutorials-book-review/</guid>
      <description>&lt;p&gt;I received a review copy of the new version of Sarah Reichhelt’s &lt;a href=&#34;https://troz.net/books/macos_tutorials/&#34;&gt;macOS by Tutorials book&lt;/a&gt; and decided to share details about the book so you can determine if it’s right for you.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whothebookisfor&#34;&gt;Who the Book is for&lt;/h3&gt;&#xA;&lt;p&gt;The book is written for people with some iOS development experience who want to learn to make Mac apps with SwiftUI. AppKit developers who want to get up to speed with SwiftUI would also benefit from this book.&lt;/p&gt;&#xA;&lt;p&gt;The book assumes the reader knows some Swift and SwiftUI. Someone with no programming experience would need to learn the basics of Swift before going through the book.&lt;/p&gt;&#xA;&lt;h3 id=&#34;bookcontents&#34;&gt;Book Contents&lt;/h3&gt;&#xA;&lt;p&gt;The title of the book gives away what the book covers. You create four Mac apps in the book, three SwiftUI apps and an AppKit menu bar app, and the book uses a tutorial format to teach the material. You learn by building the apps. The projects &lt;a href=&#34;https://github.com/trozware/mos_book_code&#34;&gt;are available on GitHub&lt;/a&gt; for you to view and to check for any mistakes you might make following the tutorials.&lt;/p&gt;&#xA;&lt;p&gt;The final section of the book covers how to distribute your Mac app.&lt;/p&gt;&#xA;&lt;p&gt;The projects have been tested and run on both Xcode 15 and 16.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatthebookdoesntcover&#34;&gt;What the Book Doesn’t Cover&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;SwiftData&lt;/li&gt;&#xA;&lt;li&gt;Core Data&lt;/li&gt;&#xA;&lt;li&gt;The Observable framework&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;thefirstswiftuiapp&#34;&gt;The First SwiftUI App&lt;/h3&gt;&#xA;&lt;p&gt;The first app you build in the book is On This Day, an app that shows information about events, births, and deaths that occurred on a particular date. You build the app over five chapters.&lt;/p&gt;&#xA;&lt;p&gt;The first chapter covers the design of the data model for the app. Topics covered in the chapter include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Fetching data from the network&lt;/li&gt;&#xA;&lt;li&gt;Decoding JSON&lt;/li&gt;&#xA;&lt;li&gt;Saving JSON to a local file&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The second chapter is where you start building the user interface for the app. The app uses a navigation split view with a sidebar and detail area. Topics covered in the chapter include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Building a sidebar&lt;/li&gt;&#xA;&lt;li&gt;Building a card view to display events&lt;/li&gt;&#xA;&lt;li&gt;Building a grid to display cards&lt;/li&gt;&#xA;&lt;li&gt;Creating multiple windows&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In the third chapter you add a toolbar to the window and add menus to the app. Topics covered in the chapter include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Adding a menu to the menu bar&lt;/li&gt;&#xA;&lt;li&gt;Adding menu items to an existing menu&lt;/li&gt;&#xA;&lt;li&gt;Using a picker as a menu item&lt;/li&gt;&#xA;&lt;li&gt;Adding a search field to the toolbar to filter what appears in the detail view&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The fourth chapter covers using tables and custom views. Topics covered in the chapter include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Getting the app to show the event data as a table or grid&lt;/li&gt;&#xA;&lt;li&gt;Using the &lt;code&gt;@SceneStorage&lt;/code&gt; property wrapper to save settings for each window&lt;/li&gt;&#xA;&lt;li&gt;Adding an inspector&lt;/li&gt;&#xA;&lt;li&gt;Creating a custom date picker to let people choose a date to view events&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The final chapter covers the following topics:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Adding a preferences window to the app&lt;/li&gt;&#xA;&lt;li&gt;Adding an app icon&lt;/li&gt;&#xA;&lt;li&gt;Customizing the app’s About box&lt;/li&gt;&#xA;&lt;li&gt;Replacing the default Help menu item with an item that takes you to a website&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;themenubarapp&#34;&gt;The Menu Bar App&lt;/h3&gt;&#xA;&lt;p&gt;The second app you create in the book is a Pomodoro timer menu bar app. You build the app over three chapters.&lt;/p&gt;&#xA;&lt;p&gt;In the first chapter you convert the standard AppKit app project to a menu bar app. A big part of the chapter is adding the menu items to the menu bar. Topics covered include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Adding menu items in a storyboard&lt;/li&gt;&#xA;&lt;li&gt;Adding dynamic menu items in code&lt;/li&gt;&#xA;&lt;li&gt;Using custom views in menu items.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The second chapter covers working with timers, alerts, and notifications. You will learn how to start and stop pomodoro tasks.&lt;/p&gt;&#xA;&lt;p&gt;In the final chapter you learn how to add your own tasks to the app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thedocument-basedapp&#34;&gt;The Document-Based App&lt;/h3&gt;&#xA;&lt;p&gt;The third app you create in the book is a Markdown editor with live preview. You build the app over two chapters.&lt;/p&gt;&#xA;&lt;p&gt;The first chapter covers the following topics:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Creating and configuring a document-based app&lt;/li&gt;&#xA;&lt;li&gt;Adding a Swift package to a project&lt;/li&gt;&#xA;&lt;li&gt;Using AppKit views in a SwiftUI app&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The second chapter focuses on adding menu controls to the app. The chapter covers the following topics:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Adding a menu to the app to show the HTML using a CSS stylesheet&lt;/li&gt;&#xA;&lt;li&gt;Adding menu items that are specific to a single window&lt;/li&gt;&#xA;&lt;li&gt;Exporting a document to a file&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;thefinalapp&#34;&gt;The Final App&lt;/h3&gt;&#xA;&lt;p&gt;The final app you build is an app that provides a GUI for the &lt;code&gt;sips&lt;/code&gt; Terminal command. The &lt;code&gt;sips&lt;/code&gt; command manipulates images. You build the app over three chapters.&lt;/p&gt;&#xA;&lt;p&gt;The first chapter introduces you to the Terminal and shows you how to use the &lt;code&gt;Process&lt;/code&gt; class to run Terminal commands from a Mac GUI app.&lt;/p&gt;&#xA;&lt;p&gt;In the second chapter you build the user interface for the app. The chapter covers the following topics:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Opening files with SwiftUI’s file importer&lt;/li&gt;&#xA;&lt;li&gt;Dragging and dropping files and folders to a SwiftUI view&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The final chapter covers adding support for macOS automation features to the app. The chapter covers the following topics:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Creating a service that can be accessed from the macOS Services menu&lt;/li&gt;&#xA;&lt;li&gt;Creating an app intent that can be used by the Shortcuts app or Siri&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;distributingyourapp&#34;&gt;Distributing Your App&lt;/h3&gt;&#xA;&lt;p&gt;The final two chapters of the book cover how to distribute your Mac apps so other people can use them. The first chapter covers how to put your app on the Mac App Store.&lt;/p&gt;&#xA;&lt;p&gt;The second chapter shows you how to distribute your app outside the Mac App Store. You learn how to notarize your app and create a DMG disk image for your app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;shouldyoubuythisbook&#34;&gt;Should You Buy This Book?&lt;/h3&gt;&#xA;&lt;p&gt;I recommend buying the book under the following conditions:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;You want to learn how to make SwiftUI Mac apps&lt;/li&gt;&#xA;&lt;li&gt;You know some Swift&lt;/li&gt;&#xA;&lt;li&gt;You like learning through tutorials where you build apps&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Save Data in Your Swift App with PropertyListEncoder</title>
      <link>https://swiftdevjournal.com/save-data-in-your-swift-app-with-propertylistencoder/</link>
      <pubDate>Wed, 29 May 2024 19:41:28 +0000</pubDate>
      <guid>https://swiftdevjournal.com/save-data-in-your-swift-app-with-propertylistencoder/</guid>
      <description>&lt;p&gt;Apple provides a &lt;code&gt;PropertyListEncoder&lt;/code&gt; class to save data as a dictionary in a property list file. If your app’s data can be saved to a dictionary, using &lt;code&gt;PropertyListEncoder&lt;/code&gt; provides a relatively easy way to save the data.&lt;/p&gt;&#xA;&lt;p&gt;You must do the following to save app data with &lt;code&gt;PropertyListEncoder&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a struct or class that conforms to the &lt;code&gt;Codable&lt;/code&gt; protocol.&lt;/li&gt;&#xA;&lt;li&gt;Create a &lt;code&gt;CodingKeys&lt;/code&gt; enum for the properties in your struct or class.&lt;/li&gt;&#xA;&lt;li&gt;Create a property list encoder and encode the data.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;creatingthestructorclass&#34;&gt;Creating the Struct or Class&lt;/h3&gt;&#xA;&lt;p&gt;For this article, I’m going to use a stripped down version of a struct I created in &lt;a href=&#34;https://www.checksimsoftware.com/phel/&#34;&gt;Phel&lt;/a&gt; to store an Apple help book’s &lt;code&gt;Info.plist&lt;/code&gt; file. The following block shows the code for the struct:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HelpBookInfo&lt;/span&gt;: Codable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// The values are placeholder values.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// The app has a view to set the values.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; appTitle = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;My App&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; bookTitle = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;My App Help&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; bundleIdentifier = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;com.CompanyName.MyApp.Help&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every property in the struct or class must also conform to &lt;code&gt;Codable&lt;/code&gt;. If you can’t get the struct’s properties to conform to &lt;code&gt;Codable&lt;/code&gt;, you must use the &lt;code&gt;NSKeyedArchiver&lt;/code&gt; class to create the property list. The following article shows you how to use &lt;code&gt;NSKeyedArchiver&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-saving-with-nskeyedarchiver/&#34;&gt;Saving with NSKeyedArchiver&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingacodingkeysenum&#34;&gt;Creating a CodingKeys Enum&lt;/h3&gt;&#xA;&lt;p&gt;It’s not mandatory to create a &lt;code&gt;CodingKeys&lt;/code&gt; enum, but if you don’t create the enum, the property list encoder uses the name of the property as the key. In many cases the key must have a specific value. The &lt;code&gt;CodingKeys&lt;/code&gt; enum lets you save the property list with the correct key names while letting you use clear property names in your code.&lt;/p&gt;&#xA;&lt;p&gt;Add the &lt;code&gt;CodingKeys&lt;/code&gt; enum inside your struct or class. Add a case for each property. The following code shows the enum for the &lt;code&gt;HelpBookInfo&lt;/code&gt; struct.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CodingKeys&lt;/span&gt;: String, CodingKey {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; appTitle = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CFBundleName&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; bookTitle = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HPDBookTitle&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; bundleIdentifier = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CFBundleIdentifier&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When saving the property list, the file will use the key &lt;code&gt;CFBundleName&lt;/code&gt; to store the name of the app, the key &lt;code&gt;HPDBookTitle&lt;/code&gt; to store the name of the help book, and the key &lt;code&gt;CFBundleIdentifier&lt;/code&gt; to store the help book’s bundle identifier.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingthepropertylistencoder&#34;&gt;Creating the Property List Encoder&lt;/h3&gt;&#xA;&lt;p&gt;Now you can create the property list encoder to save data. Start by creating an instance of &lt;code&gt;PropertyListEncoder&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Property lists have two possible formats: XML and binary. Set the encoder’s &lt;code&gt;outputFormat&lt;/code&gt; property to set the format.&lt;/p&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;encode&lt;/code&gt; method to save the data. Supply the value that you want to encode. The &lt;code&gt;encode&lt;/code&gt; method can throw errors so you must wrap the call in a &lt;code&gt;do-try-catch&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;p&gt;Adding the following method to the &lt;code&gt;HelpBookInfo&lt;/code&gt; struct saves the help book information to an XML property list:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;() -&amp;gt; Data? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; encoder = PropertyListEncoder()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  encoder.outputFormat = .xml&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; encoder.encode(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Running a Command-Line Program from a Mac App</title>
      <link>https://swiftdevjournal.com/running-a-command-line-program-from-a-mac-app/</link>
      <pubDate>Mon, 08 Apr 2024 17:39:53 +0000</pubDate>
      <guid>https://swiftdevjournal.com/running-a-command-line-program-from-a-mac-app/</guid>
      <description>&lt;p&gt;Apple provides the &lt;code&gt;Process&lt;/code&gt; class that lets you run Terminal commands and command-line programs inside a Mac app. If you were creating a git GUI client, such as SourceTree or Tower, you would use the &lt;code&gt;Process&lt;/code&gt; class to run git commands from your app.&lt;/p&gt;&#xA;&lt;p&gt;To run a command-line program from your Mac app, you must do the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a &lt;code&gt;Process&lt;/code&gt; instance&lt;/li&gt;&#xA;&lt;li&gt;Configure the process&lt;/li&gt;&#xA;&lt;li&gt;Run the process&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;createtheprocess&#34;&gt;Create the Process&lt;/h3&gt;&#xA;&lt;p&gt;Creating a process is the easiest step. Call the &lt;code&gt;Process&lt;/code&gt; class’s initializer.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; task = Process()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;configuretheprocess&#34;&gt;Configure the Process&lt;/h3&gt;&#xA;&lt;p&gt;What you must configure depends on the command or program you want to run. You must set the executable URL, the location of the command or program you want to run. Some other things you may need to configure include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Arguments to pass to the process&lt;/li&gt;&#xA;&lt;li&gt;The current directory&lt;/li&gt;&#xA;&lt;li&gt;Environment variables&lt;/li&gt;&#xA;&lt;li&gt;Standard error&lt;/li&gt;&#xA;&lt;li&gt;Standard input&lt;/li&gt;&#xA;&lt;li&gt;Standard output&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In my help book building app &lt;a href=&#34;https://www.checksimsoftware.com/phel/&#34;&gt;Phel&lt;/a&gt;, I run the &lt;code&gt;hiutil&lt;/code&gt; command to index the help book. I configure the following items to run the command:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The executable URL, which is &lt;code&gt;usr/bin/hiutil&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;The directory to run the command, which is the Resources folder inside the help book bundle.&lt;/li&gt;&#xA;&lt;li&gt;The arguments, which are &lt;code&gt;-I&lt;/code&gt;, &lt;code&gt;lsm&lt;/code&gt;, &lt;code&gt;-Caf&lt;/code&gt;, the name of the index file, &lt;code&gt;-vv&lt;/code&gt;, and &lt;code&gt;.&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I must run the &lt;code&gt;hiutil&lt;/code&gt; command a second time to generate a spotlight index file. I replace the &lt;code&gt;lsm&lt;/code&gt; argument with &lt;code&gt;corespotlight&lt;/code&gt; and supply the name of the spotlight index file.&lt;/p&gt;&#xA;&lt;h3 id=&#34;runtheprocess&#34;&gt;Run the Process&lt;/h3&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;run&lt;/code&gt; function inside a &lt;code&gt;do-catch&lt;/code&gt; block to run a process.&lt;/p&gt;&#xA;&lt;p&gt;The following code runs the &lt;code&gt;hiutil&lt;/code&gt; to generate an index file for an Apple help book:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// location is the URL of the help book bundle.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;createIndexFile&lt;/span&gt;(location: URL) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; task = Process()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  task.executableURL = URL(fileURLWithPath: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;usr/bin/hiutil&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Get to the Resources folder in the help book bundle.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; contentsFolder = location.appendingPathComponent(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Contents&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    conformingTo: .data)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; resourcesFolder = contentsFolder.appendingPathComponent(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Resources&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    conformingTo: .data)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  task.currentDirectoryURL = resourcesFolder&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// indexFile is the name of the file the hiutil command creates.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  task.arguments = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-I&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;lsm&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-Caf&amp;#34;&lt;/span&gt;, indexFile, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-vv&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; task.run()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Creating a UIKit Xcode Project</title>
      <link>https://swiftdevjournal.com/creating-a-uikit-xcode-project/</link>
      <pubDate>Mon, 12 Feb 2024 19:02:16 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-a-uikit-xcode-project/</guid>
      <description>&lt;p&gt;A common problem people learning UIKit have when following a tutorial is that what they see in Xcode does not match what the tutorial shows. The tutorial shows a view controller file, but they see a content view file.&lt;/p&gt;&#xA;&lt;p&gt;The most common cause of this problem is creating an Xcode project that uses SwiftUI instead of UIKit. When you create a new project in Xcode, the default is to create a SwiftUI project.&lt;/p&gt;&#xA;&lt;p&gt;To create an Xcode project that uses UIKit, you must create an iOS app project and tell Xcode to use a storyboard for the user interface. UIKit uses storyboards, and SwiftUI doesn’t.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createaniosappproject&#34;&gt;Create an iOS App Project&lt;/h3&gt;&#xA;&lt;p&gt;In Xcode choose File &amp;gt; New &amp;gt; Project to create a new project. The New Project Assistant opens.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeCreateiOSAppProject.png&#34; alt=&#34;create iOS Xcode project&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click on iOS at the top of the assistant to see the iOS app project templates. Choose either App or Document App. If you’re not sure, choose App. Click the Next button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;choosestoryboardfortheuserinterface&#34;&gt;Choose Storyboard for the User Interface&lt;/h3&gt;&#xA;&lt;p&gt;When you click the Next button, the New Project Assistant takes you to the next step in creating the project.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeChooseStoryboard.png&#34; alt=&#34;choose storyboard&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Choose Storyboard from the Interface menu to create a UIKIt project.&lt;/p&gt;&#xA;&lt;p&gt;If you don’t see an Interface menu (or a menu with a similar name), click the Previous button and make sure you choose an iOS app project. Xcode’s multi-platform project templates create SwiftUI projects.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>How to Learn SwiftUI to Develop Mac Apps</title>
      <link>https://swiftdevjournal.com/how-to-learn-swiftui-to-develop-mac-apps/</link>
      <pubDate>Mon, 05 Feb 2024 19:09:03 +0000</pubDate>
      <guid>https://swiftdevjournal.com/how-to-learn-swiftui-to-develop-mac-apps/</guid>
      <description>&lt;p&gt;A common complaint I hear online from Mac developers is that all the SwiftUI learning material focuses on iOS development, and there’s nothing on Mac development. This article provides advice on learning SwiftUI for Mac development.&lt;/p&gt;&#xA;&lt;h3 id=&#34;alotofiosswiftuilearningmaterialalsoworksonmac&#34;&gt;A lot of iOS SwiftUI learning material also works on Mac&lt;/h3&gt;&#xA;&lt;p&gt;Mac developers have to accept the fact that iOS development is much more popular than Mac development. People creating SwiftUI tutorials, videos, and courses are going to focus on iOS developers.&lt;/p&gt;&#xA;&lt;p&gt;The good news with SwiftUI is that most of the iOS learning material also applies to Mac development. Apple created SwiftUI so developers can create user interfaces for all of their platforms with one framework. If you find a SwiftUI tutorial or course that you like, such as &lt;a href=&#34;https://www.hackingwithswift.com/100/swiftui&#34;&gt;Hacking with Swift’s 100 Days of SwiftUI course&lt;/a&gt;, you can use the tutorial or course to make Mac apps. You may have to make some changes to get things to work on Mac.&lt;/p&gt;&#xA;&lt;p&gt;Lists are one area of SwiftUI where there are large differences between iOS and Mac. If you read an article about lists and try to use the code in a Mac app, you’ll run into problems. The following articles cover those differences:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/working-with-lists-in-multiplatform-swiftui-apps/&#34;&gt;Working with Lists in Multiplatform SwiftUI Apps&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/removing-items-from-swiftui-lists-in-mac-apps/&#34;&gt;Removing Items from SwiftUI Lists in Mac Apps&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/moving-list-items-using-drag-and-drop-in-swiftui-mac-apps/&#34;&gt;Moving List Items Using Drag and Drop in SwiftUI Mac Apps&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;youcanuseappkitviewsinswiftuimacapps&#34;&gt;You can use AppKit views in SwiftUI Mac apps&lt;/h3&gt;&#xA;&lt;p&gt;SwiftUI is not a finished framework, especially on Mac. Some views that Mac apps need do not have native SwiftUI equivalents, and some of SwiftUI’s views do not work well on Mac. A workaround for SwiftUI’s Mac limitations is to use AppKit views in your app.&lt;/p&gt;&#xA;&lt;p&gt;To use an AppKit view in a SwiftUI Mac app, create a struct that conforms to the &lt;code&gt;NSViewRepresentable&lt;/code&gt; protocol. My &lt;a href=&#34;https://www.swiftdevjournal.com/using-a-uikit-or-appkit-view-in-swiftui/&#34;&gt;Using a UIKit or AppKIt View in SwiftUI article&lt;/a&gt; provides more details on using AppKit views in a SwiftUI app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;swiftuiresourcesformacdevelopment&#34;&gt;SwiftUI resources for Mac development&lt;/h3&gt;&#xA;&lt;p&gt;To address complaints about a lack of learning material on Mac development, I compiled &lt;a href=&#34;https://www.swiftdevjournal.com/resources-for-learning-mac-development/&#34;&gt;a list of Mac development resources&lt;/a&gt;. Many of those resources cover using SwiftUI for Mac development.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/&#34;&gt;This site&lt;/a&gt; has a number of SwiftUI articles, most of which apply to Mac development. You can see a complete list of articles on the &lt;a href=&#34;https://www.swiftdevjournal.com/posts/&#34;&gt;Articles page&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Deleting an Xcode Project’s Git Repository</title>
      <link>https://swiftdevjournal.com/deleting-an-xcode-projects-git-repository/</link>
      <pubDate>Thu, 25 Jan 2024 18:48:49 +0000</pubDate>
      <guid>https://swiftdevjournal.com/deleting-an-xcode-projects-git-repository/</guid>
      <description>&lt;p&gt;Deleting a git repository for an Xcode project is relatively easy: move the folder that holds the git repository out of the project folder. But the Finder makes locating the repository folder difficult. In this article you will learn how to find the repository folder so you can delete it.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whereisthegitrepository&#34;&gt;Where is the git repository?&lt;/h3&gt;&#xA;&lt;p&gt;The git repository is in a &lt;code&gt;.git&lt;/code&gt; folder inside the project folder. If you go to the project folder in the Finder, you won’t see the &lt;code&gt;.git&lt;/code&gt; folder. Why can’t you see it?&lt;/p&gt;&#xA;&lt;p&gt;You can’t see the &lt;code&gt;.git&lt;/code&gt; folder in the Finder because the Finder hides files and folders that start with a dot. To see the &lt;code&gt;.git&lt;/code&gt; folder in the Finder, press Cmd-Shift-Dot. Pressing Cmd-Shift-Dot shows hidden files and folders.&lt;/p&gt;&#xA;&lt;p&gt;Press Cmd-Shift-Dot a second time to stop showing the hidden files and folders in the Finder.&lt;/p&gt;&#xA;&lt;h3 id=&#34;deletingtherepository&#34;&gt;Deleting the repository&lt;/h3&gt;&#xA;&lt;p&gt;Move the &lt;code&gt;.git&lt;/code&gt; folder out of the project folder, and git will stop tracking changes in your project. You will normally move the &lt;code&gt;.git&lt;/code&gt; folder to the Trash.&lt;/p&gt;&#xA;&lt;p&gt;If you want to create a new git repository for your project after removing the previous one, choose Integrate &amp;gt; New Git Repository in Xcode. Older versions of Xcode have a Source Control menu instead of an Integrate menu.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wanttolearnmoreaboutversioncontrol&#34;&gt;Want to learn more about git?&lt;/h3&gt;&#xA;&lt;p&gt;Check out my &lt;a href=&#34;https://www.swiftdevjournal.com/version-control-book/&#34;&gt;version control book&lt;/a&gt;. It shows you how to do the most common git tasks without leaving Xcode. Some of the material covered in the book includes cloning projects from GitHub, branching, and going back to earlier versions of your project.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Where is the Info.plist file?</title>
      <link>https://swiftdevjournal.com/where-is-the-info-plist-file/</link>
      <pubDate>Tue, 02 Jan 2024 19:20:01 +0000</pubDate>
      <guid>https://swiftdevjournal.com/where-is-the-info-plist-file/</guid>
      <description>&lt;p&gt;Recent versions of Xcode do not add an &lt;code&gt;Info.plist&lt;/code&gt; file to new iOS app projects. How do you add settings to your app that you would normally place in &lt;code&gt;Info.plist&lt;/code&gt;?&lt;/p&gt;&#xA;&lt;p&gt;Xcode’s project editor has an Info section for the app target, where you can add the settings. Take the following steps to access the Info section:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Select your project from the project navigator on the left side of the project window to open the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Select your app from the target list on the left side of the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Click the Info button at the top of the project editor.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/InfoPlistTargetSettings.png&#34; alt=&#34;Info plist target settings&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the top of the Info section is a Custom Target Properties list. To add an item to the Info section, move the mouse arrow over one of the keys in the list. Tiny buttons to add and remove an item will appear on the right side of the key where the mouse arrow is. Click the Add (+) button to add a setting to the Info section.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Dealing with the init(destination:tag:selection ) was deprecated in iOS 16.0 message</title>
      <link>https://swiftdevjournal.com/dealing-with-the-initdestinationtagselection-was-deprecated-in-ios-16-0-message/</link>
      <pubDate>Thu, 14 Dec 2023 19:36:59 +0000</pubDate>
      <guid>https://swiftdevjournal.com/dealing-with-the-initdestinationtagselection-was-deprecated-in-ios-16-0-message/</guid>
      <description>&lt;p&gt;People starting out with SwiftUI development may get a message like the following from Xcode when building their project:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;`init(destination:isActive:label:)’ was deprecated in iOS 16.0: use NavigationLink(value:label:) inside a NavigationStack or NavigationSplitView&lt;/p&gt;&#xA;&lt;p&gt;‘init(destination:tag:selection????️ )’ was deprecated in iOS 16.0: use NavigationLink(value????️ ), or navigationDestination(isPresented:destination:), inside a NavigationStack or NavigationSplitView&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;whyareyougettingthismessage&#34;&gt;Why are you getting this message?&lt;/h3&gt;&#xA;&lt;p&gt;You are getting this message because you are using &lt;code&gt;NavigationView&lt;/code&gt; in your user interface.&lt;/p&gt;&#xA;&lt;p&gt;The original version of SwiftUI used navigation views to navigate from one screen to another in an app and for master-detail interfaces with split views on iPad. In iOS 16 Apple replaced &lt;code&gt;NavigationView&lt;/code&gt; with &lt;code&gt;NavigationStack&lt;/code&gt; and &lt;code&gt;NavigationSplitView&lt;/code&gt; for navigation.&lt;/p&gt;&#xA;&lt;p&gt;The message is telling you to replace &lt;code&gt;NavigationView&lt;/code&gt; in your app with either &lt;code&gt;NavigationStack&lt;/code&gt; or &lt;code&gt;NavigationSplitView&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;NavigationStack&lt;/code&gt; and &lt;code&gt;NavigationSplitView&lt;/code&gt; don’t run on earlier iOS versions. If you want your SwiftUI app to run on iOS 15, you must use &lt;code&gt;NavigationView&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;isthemessageaproblem&#34;&gt;Is the message a problem?&lt;/h3&gt;&#xA;&lt;p&gt;Not currently. The message is a compiler warning, not an error. Your project will build and run, assuming there are no errors in the rest of your code.&lt;/p&gt;&#xA;&lt;p&gt;Eventually Apple will stop supporting iOS 15. A future version of Xcode will drop support for building an app that runs on iOS 15. For reference Xcode 14 does not support iOS versions older than iOS 11. When Apple releases a version of Xcode that does not support building an app that runs on iOS 15, the message will be a problem.&lt;/p&gt;&#xA;&lt;h3 id=&#34;howdoyouremovethemessage&#34;&gt;How do you remove the message?&lt;/h3&gt;&#xA;&lt;p&gt;Use either &lt;code&gt;NavigationStack&lt;/code&gt; or &lt;code&gt;NavigationSplitView&lt;/code&gt; instead of &lt;code&gt;NavigationView&lt;/code&gt; in your app. Apple provides the following guide to migrate code from &lt;code&gt;NavigationView&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://developer.apple.com/documentation/swiftui/migrating-to-new-navigation-types&#34;&gt;Migrating to new navigation types&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you are following a tutorial that uses &lt;code&gt;NavigationView&lt;/code&gt;, find a more recent tutorial that uses the newer navigation APIs.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Dealing with Core Data Duplicate Class Errors</title>
      <link>https://swiftdevjournal.com/dealing-with-core-data-duplicate-class-errors/</link>
      <pubDate>Mon, 20 Nov 2023 18:23:29 +0000</pubDate>
      <guid>https://swiftdevjournal.com/dealing-with-core-data-duplicate-class-errors/</guid>
      <description>&lt;p&gt;Many people learning Core Data take the following steps when creating their first Core Data app:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Create a new Xcode project that uses Core Data.&lt;/li&gt;&#xA;&lt;li&gt;Create Code Data entities and relationships in Xcode’s data model editor.&lt;/li&gt;&#xA;&lt;li&gt;Create subclasses for their entities by choosing Editor &amp;gt; Create NSManagedObject Subclass in Xcode.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;They build the project and get the following build error:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Invalid redeclaration of Entity&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Where &lt;code&gt;Entity&lt;/code&gt; is the name of a Core Data entity.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatcausestheerror&#34;&gt;What Causes the Error?&lt;/h3&gt;&#xA;&lt;p&gt;When you create a new Xcode project that uses Core Data, Xcode is set to automatically create NSManagedObject subclasses for your Core Data entities. Xcode creates the subclasses when you build the project.&lt;/p&gt;&#xA;&lt;p&gt;The source code files Xcode creates are in the project’s derived data location. You can’t see the files in the left side of the project window like the other source code files in your project. You’re not meant to access and edit the source code files Xcode creates for your Core Data entities. The point of Xcode creating the files is to automatically update the files when you make changes to the data model.&lt;/p&gt;&#xA;&lt;p&gt;If you create NSManagedObject subclasses from Xcode’s Editor menu, you wind up with two files for each subclass: the one Xcode automatically generates and the one you create.&lt;/p&gt;&#xA;&lt;p&gt;When you have two classes with the same name, Xcode gives you the “Invalid redeclaration” error, and your project won’t build.&lt;/p&gt;&#xA;&lt;h3 id=&#34;howdoyoufixtheerror&#34;&gt;How do You Fix the Error?&lt;/h3&gt;&#xA;&lt;p&gt;There are two ways to fix the error. The first way is to remove the class files you added and let Xcode generate the classes for you.&lt;/p&gt;&#xA;&lt;p&gt;The second way is to tell Xcode not to generate class files for your Core Data entities by choosing Manual/None from the Codegen menu in Xcode’s data model inspector. Choose View &amp;gt; Inspectors &amp;gt; Data Model in Xcode to access the data model inspector. Read the following article for screenshots and more details on Core Data class generation options:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/core-data-code-generation/&#34;&gt;Core Data Code Generation&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Highlighting the Selected Item Button in a SwiftUI List</title>
      <link>https://swiftdevjournal.com/highlighting-the-selected-item-button-in-a-swiftui-list/</link>
      <pubDate>Mon, 09 Oct 2023 17:55:44 +0000</pubDate>
      <guid>https://swiftdevjournal.com/highlighting-the-selected-item-button-in-a-swiftui-list/</guid>
      <description>&lt;p&gt;If you use a button for list items in SwiftUI, the list item does not highlight when you select it. This is expected behavior for a bordered button. But some apps need to use buttons that look like text to perform actions when selecting the list item. If you have a button that looks like text, you want to highlight the selection so people can easily see the selected item.&lt;/p&gt;&#xA;&lt;p&gt;How do you highlight the selected item? You must do two things to highlight the selected item. First, you must set the background color for the list row. Second, you must set the foreground color for the list item.&lt;/p&gt;&#xA;&lt;h3 id=&#34;settingthebackgroundcolor&#34;&gt;Setting the Background Color&lt;/h3&gt;&#xA;&lt;p&gt;Add a &lt;code&gt;.listRowBackground&lt;/code&gt; modifier to the button to set the background color. Use the accent color for the selected item to highlight it and the clear color for the other items to match the standard selection highlighting.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.listRowBackground(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.selection == item ? Color.accentColor : Color(.clear))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;settingtheforegroundcolor&#34;&gt;Setting the Foreground Color&lt;/h3&gt;&#xA;&lt;p&gt;When you select an item from a SwiftUI list in an app running in light mode, the text color for the item changes from a dark color to a light color. You must set the color based on the current color scheme or else the text of the selected item will be tough to read.&lt;/p&gt;&#xA;&lt;p&gt;Start by adding an &lt;code&gt;@Environment&lt;/code&gt; property to your SwiftUI view that stores the current color scheme: light or dark.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Environment(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.colorScheme) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; colorScheme&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, create computed properties for the item color based on whether or not it’s selected. Use white for the selected item. For unselected items make the text white in dark mode and black in light mode.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; unselectedItemTextColor : Color {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; (colorScheme == .dark ? Color(.white) : Color(.black))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; selectedItemTextColor : Color {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Color(.white)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally add a &lt;code&gt;.foregroundColor&lt;/code&gt; modifier to the button. Use the selected item color for the selected item and the unselected item color for the other items.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .foregroundColor(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.selection == item ? selectedItemTextColor : unselectedItemTextColor)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Creating a SwiftUI Toolbar Button with an Image and a Label</title>
      <link>https://swiftdevjournal.com/creating-a-swiftui-toolbar-button-with-an-image-and-a-label/</link>
      <pubDate>Mon, 02 Oct 2023 19:30:30 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-a-swiftui-toolbar-button-with-an-image-and-a-label/</guid>
      <description>&lt;p&gt;Many toolbar buttons in Mac and iOS apps include an image and a label. The Mac apps Finder, Mail, and Pages are examples of apps whose toolbar buttons have an image and a label.&lt;/p&gt;&#xA;&lt;p&gt;If you try to create a button in a SwiftUI toolbar with an image and a label, you will notice the label does not appear. You must do the following to create a toolbar button with an image and a label:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a label style for the button.&lt;/li&gt;&#xA;&lt;li&gt;Add a &lt;code&gt;.labelStyle&lt;/code&gt; modifier to your button label and use the label style you created.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;creatingalabelstyle&#34;&gt;Creating a Label Style&lt;/h3&gt;&#xA;&lt;p&gt;To create a label style, you must create a struct that conforms to the &lt;code&gt;LabelStyle&lt;/code&gt; protocol. Add a &lt;code&gt;makeBody&lt;/code&gt; function to the struct that returns a SwiftUI view.&lt;/p&gt;&#xA;&lt;p&gt;A label style for a toolbar button should create a VStack with the image first and the text label second. Supply a font to use for the image and the label in the VStack.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VerticalLabelStyle&lt;/span&gt;: LabelStyle {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeBody&lt;/span&gt;(configuration: Configuration) -&amp;gt; some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    VStack {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      configuration.icon.font(.headline)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      configuration.title.font(.footnote)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;addthe.labelstylemodifier&#34;&gt;Add the .labelStyle Modifier&lt;/h3&gt;&#xA;&lt;p&gt;After creating the label style for your toolbar button, add a &lt;code&gt;.labelStyle&lt;/code&gt; modifier to the button’s label and supply the name of the struct you created for the label style. The following code shows an example of a SwiftUI button that uses a custom label style:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  isPublishing = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Label(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Publish&amp;#34;&lt;/span&gt;, systemImage: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;book.closed.fill&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .labelStyle(VerticalLabelStyle())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}).accessibilityLabel(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Publish Book&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;credits&#34;&gt;Credits&lt;/h3&gt;&#xA;&lt;p&gt;The answer from Eduardo to the following Stack Overflow question helped me with the code for this article:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://stackoverflow.com/questions/64085819/add-button-with-image-and-text-in-toolbaritem-swiftui&#34;&gt;Add Button with Image and Text in ToolbarItem SwiftUI&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Adding a Help Menu to a SwiftUI App</title>
      <link>https://swiftdevjournal.com/adding-a-help-menu-to-a-swiftui-app/</link>
      <pubDate>Mon, 11 Sep 2023 17:56:46 +0000</pubDate>
      <guid>https://swiftdevjournal.com/adding-a-help-menu-to-a-swiftui-app/</guid>
      <description>&lt;p&gt;When you create and run a SwiftUI Mac app project, the Help menu has a menu item named &lt;code&gt;AppName Help&lt;/code&gt;, where &lt;code&gt;AppName&lt;/code&gt; is the name of your app. If you choose that menu item, an alert opens saying help isn’t available for the app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;helpbooks&#34;&gt;Help Books&lt;/h3&gt;&#xA;&lt;p&gt;The included menu item works only if your app has a Help Book bundled in the app. Many of Apple’s apps have Help Books. Choose Help &amp;gt; Xcode Help in Xcode to see an example of a Help Book.&lt;/p&gt;&#xA;&lt;p&gt;Creating Help Books is painful. Apple’s &lt;a href=&#34;https://developer.apple.com/library/archive/documentation/Carbon/Conceptual/ProvidingUserAssitAppleHelp/user_help_intro/user_assistance_intro.html&#34;&gt;Help Book Programming Guide&lt;/a&gt; was last updated in 2013, and there aren’t many articles online on creating Help Books.&lt;/p&gt;&#xA;&lt;h3 id=&#34;takeuserstoyoursite&#34;&gt;Take Users to Your Site&lt;/h3&gt;&#xA;&lt;p&gt;For most apps it’s easier to add a page to your app’s website with your app’s help and add a menu item to go that page. You can even include a link on the page for people to download a user guide for your app. Creating a menu item that takes someone to your site involves the following steps:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a view for the menu item.&lt;/li&gt;&#xA;&lt;li&gt;Create a SwiftUI link for the menu item.&lt;/li&gt;&#xA;&lt;li&gt;Add the menu item to the menu bar.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;creatingthelinkandmenuitem&#34;&gt;Creating the Link and Menu Item&lt;/h4&gt;&#xA;&lt;p&gt;A SwiftUI link takes two arguments. The first argument is the link name, which is the menu item text for menus. The second argument is the link destination. The following code shows an example of a menu item with a link:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HelpMenu&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Group {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Link(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Your App Website&amp;#34;&lt;/span&gt;, destination: URL(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        string: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://www.your-site.com/your-app/&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Place other Help menu items here.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;addingthemenuitemtothemenubar&#34;&gt;Adding the Menu Item to the Menu Bar&lt;/h4&gt;&#xA;&lt;p&gt;Add a &lt;code&gt;.commands&lt;/code&gt; modifier to the window group or document group in the &lt;code&gt;App&lt;/code&gt; struct for your app. Add a command group for the menu, replacing the default Help menu item with your Help menu items.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.commands {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CommandGroup(replacing: .help) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    HelpMenu()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;doyouwanttoaddahelpbooktoyourapp&#34;&gt;Do you want to add a help book to your app?&lt;/h3&gt;&#xA;&lt;p&gt;Earlier in this article I mentioned that creating a help book for a Mac app is painful. To help developers deal with this pain, I’m developing &lt;a href=&#34;https://www.checksimsoftware.com/phel/&#34;&gt;Phel&lt;/a&gt;, an app that creates help books from Markdown files.&lt;/p&gt;&#xA;&lt;p&gt;Write your help pages in Markdown, import the help pages and images, hit the Publish button, and get an indexed help book you can add to your Xcode project.&lt;/p&gt;&#xA;&lt;p&gt;You can download and try Phel at the &lt;a href=&#34;https://www.checksimsoftware.com/phel/&#34;&gt;Phel page&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Showing a SwiftUI sheet from a Mac Menu</title>
      <link>https://swiftdevjournal.com/showing-a-swiftui-sheet-from-a-mac-menu/</link>
      <pubDate>Wed, 30 Aug 2023 19:13:28 +0000</pubDate>
      <guid>https://swiftdevjournal.com/showing-a-swiftui-sheet-from-a-mac-menu/</guid>
      <description>&lt;p&gt;Most articles on showing sheets in SwiftUI apps show an example of a button with a &lt;code&gt;.sheet&lt;/code&gt; modifier that shows the sheet. But if you try to apply the example to a menu in a Mac app,&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PreviewMenu&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; isPreviewing = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      isPreviewing = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Preview&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })          &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .sheet(isPresented: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;isPreviewing) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      PreviewView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The sheet does not appear when you choose the menu item. How do you show the sheet when someone chooses the menu item?&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Add a focused value for showing the sheet.&lt;/li&gt;&#xA;&lt;li&gt;Set the focused scene value in your main view.&lt;/li&gt;&#xA;&lt;li&gt;Add the menu item to show the sheet.&lt;/li&gt;&#xA;&lt;li&gt;Add the menu item to the app’s menu bar.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Read the &lt;a href=&#34;https://www.swiftdevjournal.com/accessing-the-document-in-a-swiftui-menu/&#34;&gt;Accessing the Document in a SwiftUI Menu article&lt;/a&gt; to learn more about focused values and working with SwiftUI menus.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addafocusedvalue&#34;&gt;Add a Focused Value&lt;/h3&gt;&#xA;&lt;p&gt;Add a focused value that your app uses to control whether or not to show the sheet. In this article I’m going to use the example of a menu item that previews some content in a sheet.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ShowPreviewKey&lt;/span&gt;: FocusedValueKey {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;typealias&lt;/span&gt; Value = Binding&amp;lt;Bool&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FocusedValues&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; showPreview: Binding&amp;lt;Bool&amp;gt;? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;[ShowPreviewKey.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;] }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;[ShowPreviewKey.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;] = newValue }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;setthefocusedscenevalue&#34;&gt;Set the Focused Scene Value&lt;/h3&gt;&#xA;&lt;p&gt;After creating the focused value to show the sheet, you must make that value a focused scene value to show the sheet from a menu. Start by adding a property to the main SwiftUI view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; showingPreview: Bool = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next step is to add a &lt;code&gt;.focusedSceneValue&lt;/code&gt; modifier to the view. The first argument is the name of the variable you created for the focused value. The second argument is a binding using the property you created in the view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.focusedSceneValue(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.showPreview, &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;showingPreview)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.sheet(isPresented: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;showingPreview) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PreviewView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Apple added the &lt;code&gt;.focusedSceneValue&lt;/code&gt; modifier in macOS 12.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addthemenuitem&#34;&gt;Add the Menu Item&lt;/h3&gt;&#xA;&lt;p&gt;Menus in SwiftUI apps are SwiftUI views. To show a sheet from the menu, start by creating a property with the &lt;code&gt;@FocusedValue&lt;/code&gt; property wrapper that contains the focused value to show the sheet.&lt;/p&gt;&#xA;&lt;p&gt;Create a button for the menu item. The action for the button is to set the focused value’s wrapped value. The focused value for showing a sheet is a Boolean value so you give it the value of true, which shows the sheet when someone chooses the menu item.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PreviewMenu&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @FocusedValue(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.showPreview) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; showPreview&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      showPreview?.wrappedValue = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Preview&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .disabled(showPreview == &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;addthemenutotheapp&#34;&gt;Add the Menu to the App&lt;/h3&gt;&#xA;&lt;p&gt;After creating the menu you must add it to your app’s menu bar. Add a &lt;code&gt;.commands&lt;/code&gt; modifier to the app’s window group or document group to add the menu to the menu bar.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.commands {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Replace .newItem with wherever you want to insert your menu item.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CommandGroup(after: .newItem) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PreviewMenu()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;credits&#34;&gt;Credits&lt;/h3&gt;&#xA;&lt;p&gt;Thanks to Jason Armstrong for his answer to the following Stack Overflow question:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://stackoverflow.com/questions/71093444/calling-a-sheet-from-a-menu-item&#34;&gt;Calling a sheet from a menu item&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Showing Local HTML Content in a WKWebView</title>
      <link>https://swiftdevjournal.com/showing-local-html-content-in-a-wkwebview/</link>
      <pubDate>Mon, 07 Aug 2023 18:20:56 +0000</pubDate>
      <guid>https://swiftdevjournal.com/showing-local-html-content-in-a-wkwebview/</guid>
      <description>&lt;p&gt;Apple provides the &lt;code&gt;WKWebView&lt;/code&gt; class to show web content in Swift apps. Most apps use web views to show content from websites, but you can also show local HTML in a web view. There are two common ways to show local HTML in a web view.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Loading HTML strings&lt;/li&gt;&#xA;&lt;li&gt;Loading HTML files&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;loadinghtmlstrings&#34;&gt;Loading HTML Strings&lt;/h3&gt;&#xA;&lt;p&gt;The easiest way to display HTML content in a web view is to create a string for the HTML and call the &lt;code&gt;loadHTMLString&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; html: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webView.loadHTMLString(html, baseURL: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A common reason to load an HTML string is to preview Markdown content. You can see examples of loading HTML strings in my &lt;a href=&#34;https://github.com/SwiftDevJournal/WikiDemo&#34;&gt;WikiDemo&lt;/a&gt; and &lt;a href=&#34;https://github.com/SwiftDevJournal/SwiftUIMarkdownEditor&#34;&gt;SwiftUIMarkdownEditor&lt;/a&gt; GitHub projects.&lt;/p&gt;&#xA;&lt;p&gt;The biggest limitation of loading HTML strings and showing them in a web view is that images will not show. Inserting images in a HTML string is a security risk so the web view won’t display them.&lt;/p&gt;&#xA;&lt;h3 id=&#34;loadinghtmlfiles&#34;&gt;Loading HTML Files&lt;/h3&gt;&#xA;&lt;p&gt;If you want to show images in a web view, you must create a HTML file and show it in the web view by calling the &lt;code&gt;loadFileURL&lt;/code&gt; function. The function takes two arguments. The first argument is the URL of the file to show in the web view. The second argument is a URL that you give the web view access to read. You normally give read access to a folder that contains subfolders you want to show, such as image and CSS files.&lt;/p&gt;&#xA;&lt;p&gt;I recently added code in an app to preview EPUB books in a web view. An EPUB book has an OEBPS folder that holds most of the book’s content. The OEBPS folder has the following subfolders:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A Text folder that contains the book’s chapters.&lt;/li&gt;&#xA;&lt;li&gt;An Images folder that contains the book’s images.&lt;/li&gt;&#xA;&lt;li&gt;A Styles folder that contains any CSS files to style the book.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;To preview the book I needed to pass the URL of the current chapter’s HTML file as the first argument to &lt;code&gt;loadFileURL&lt;/code&gt; and the URL of the OEBPS folder as the second argument. Giving the web view access to the OEBPS folder gives the web view access to the images and CSS files.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; bookURL: URL&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; currentChapterFilename: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; oebpsFolder = bookURL.appendingPathComponent(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OEBPS&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; textFolder = oebpsFolder.appendingPathComponent(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Text&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; chapterFile = textFolder.appendingPathComponent(currentChapterFilename)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webView.loadFileURL(chapterFile, allowingReadAccessTo: oebpsFolder)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Running a Mac App Outside of Xcode</title>
      <link>https://swiftdevjournal.com/running-a-mac-app-outside-of-xcode/</link>
      <pubDate>Mon, 31 Jul 2023 18:56:53 +0000</pubDate>
      <guid>https://swiftdevjournal.com/running-a-mac-app-outside-of-xcode/</guid>
      <description>&lt;p&gt;When you are developing a Mac app, you run it often from Xcode. But eventually you will run it outside of Xcode. You have two ways to run a Mac app outside of Xcode.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Locate the build folder&lt;/li&gt;&#xA;&lt;li&gt;Archive and export the project&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;locatethebuildfolder&#34;&gt;Locate the Build Folder&lt;/h3&gt;&#xA;&lt;p&gt;If you’re actively developing your app, locating the app from its build folder is the easiest way to run the app outside of Xcode. In Xcode choose Product &amp;gt; Show Build Folder in Finder to show the app’s build folder.&lt;/p&gt;&#xA;&lt;p&gt;Go to the Finder. The app will be in a folder inside the Products folder. Usually the name of the folder is Debug or Release.&lt;/p&gt;&#xA;&lt;h3 id=&#34;archiveandexporttheproject&#34;&gt;Archive and Export the Project&lt;/h3&gt;&#xA;&lt;p&gt;When you have your app at a point where you can use it regularly on your Mac or share with other people, you should archive and export the project to create an app file that is not buried deep inside Xcode’s Derived Data folder.&lt;/p&gt;&#xA;&lt;p&gt;In Xcode choose Product &amp;gt; Archive to archive the project. Xcode’s Organizer window contains your app archives. Choose Window &amp;gt; Organizer in Xcode to open the Organizer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/OrganizerWindow.png&#34; alt=&#34;organizer window&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the Archives item on the left side of the Organizer to show your app’s archives. If you have archived multiple projects, you may have to choose your app from the app menu that is above the Archives item.&lt;/p&gt;&#xA;&lt;p&gt;Select the archive from the archive list and click the Distribute App button to export the archive. When you click the Distribute App button, a sheet opens asking you to choose a method of distribution. Xcode provides the following distribution methods:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;App Store Connect&lt;/li&gt;&#xA;&lt;li&gt;Developer ID&lt;/li&gt;&#xA;&lt;li&gt;Development&lt;/li&gt;&#xA;&lt;li&gt;Copy App&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The first two methods require a paid Apple developer membership. I’m not sure about the Development method. If you don’t have a paid membership or are making an app for personal use, choose Copy App and click the Next button. Choose a location to save the app and click the Export button.&lt;/p&gt;&#xA;&lt;p&gt;Now you have an app file that you can run on your Mac just like any other app. You can also use the file to copy the app to another Mac.&lt;/p&gt;&#xA;&lt;h3 id=&#34;theotherdistributionmethods&#34;&gt;The Other Distribution Methods&lt;/h3&gt;&#xA;&lt;p&gt;The App Store Connect distribution method is for apps that are going to be in the Mac App Store.&lt;/p&gt;&#xA;&lt;p&gt;The Developer ID distribution method is for apps that you are going to have people download from your own website. When you choose Developer ID, Apple notarizes the app so that people who download and install your app can trust it. The &lt;a href=&#34;https://www.swiftdevjournal.com/how-to-notarize-a-mac-app/&#34;&gt;How to Notarize a Mac App article&lt;/a&gt; has more details on the Developer ID distribution method.&lt;/p&gt;&#xA;&lt;p&gt;The Development distribution method is for creating an app file to share with people you know. When I tried the Development distribution method for a Mac app, I saw no difference between the Development and Copy App distribution methods.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Scene Editor Development: Showing a SwiftUI View Based on a Selection</title>
      <link>https://swiftdevjournal.com/scene-editor-development-showing-a-swiftui-view-based-on-a-selection/</link>
      <pubDate>Mon, 17 Jul 2023 18:34:39 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scene-editor-development-showing-a-swiftui-view-based-on-a-selection/</guid>
      <description>&lt;p&gt;The inspector for the scene editor has separate SwiftUI views for each kind of item in a SpriteKit scene. There’s a sprite inspector for sprites, a label inspector for labels, and so on.&lt;/p&gt;&#xA;&lt;p&gt;When someone selects an item from the scene graph, the inspector should show the correct view. If someone selects a sprite, the inspector view should show the sprite inspector. How do you show the correct view based on the selection?&lt;/p&gt;&#xA;&lt;p&gt;My solution is to get the class name for the selected item, add a &lt;code&gt;switch&lt;/code&gt; statement to the view body, and show the correct view based on the class name.&lt;/p&gt;&#xA;&lt;h3 id=&#34;gettingtheclassname&#34;&gt;Getting the Class Name&lt;/h3&gt;&#xA;&lt;p&gt;The inspector has a property that contains the selected item from the scene graph.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; node: SKNode&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because each kind of item in a SpriteKit scene has its own class, I can get the name of the class for the &lt;code&gt;node&lt;/code&gt; property and show the correct view based on the name of the class.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;NSObject&lt;/code&gt; is the base class for every SpriteKit class. The &lt;code&gt;NSObject&lt;/code&gt; class has a &lt;code&gt;nameOfClass&lt;/code&gt; property for Mac, but not iOS. But &lt;a href=&#34;https://stackoverflow.com/questions/24107658/get-a-user-readable-version-of-the-class-name-in-swift-in-objc-nsstringfromclas&#34;&gt;I saw on Stack Overflow&lt;/a&gt; that you can add an extension to &lt;code&gt;NSObject&lt;/code&gt; to get the name of the class on iOS.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NSObject&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;var&lt;/span&gt; nameOfClass: String {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; NSStringFromClass(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;).components(separatedBy: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;).last!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; nameOfClass: String {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; NSStringFromClass(type(of: &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;)).components(separatedBy: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;).last!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;addingaswitchstatementtotheswiftuiview&#34;&gt;Adding a Switch Statement to the SwiftUI View&lt;/h3&gt;&#xA;&lt;p&gt;Now that I can get the names of the SpriteKit classes, I can add a &lt;code&gt;switch&lt;/code&gt; statement in the SwiftUI view body and show the correct view based on the class of the selected item in the scene graph.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Inspector&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; node: SKNode&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; node.nameOfClass {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SKSpriteNode&amp;#34;&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      SpriteInspector(node: node &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;! SKSpriteNode)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SKLabelNode&amp;#34;&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      LabelInspector(node: node &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;! SKLabelNode)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SKLightNode&amp;#34;&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      LightInspector(node: node &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;! SKLightNode)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Other SpriteKit classes go here.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      EmptyView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I can safely cast with &lt;code&gt;as!&lt;/code&gt; because I know the class of the selected item.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Using ReferenceFileDocument to Save SwiftUI Documents</title>
      <link>https://swiftdevjournal.com/using-referencefiledocument-to-save-swiftui-documents/</link>
      <pubDate>Mon, 26 Jun 2023 17:59:45 +0000</pubDate>
      <guid>https://swiftdevjournal.com/using-referencefiledocument-to-save-swiftui-documents/</guid>
      <description>&lt;p&gt;When you create a SwiftUI Document App project, the Swift file for the document contains a struct for the document that conforms to &lt;code&gt;FileDocument&lt;/code&gt;. Using a struct for the document works in most cases, but you can make the document a class by conforming to &lt;code&gt;ReferenceFileDocument&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whentomakeyourswiftuidocumentaclass&#34;&gt;When to Make Your SwiftUI Document a Class&lt;/h3&gt;&#xA;&lt;p&gt;The most common reason to use a class for a SwiftUI document is to update SwiftUI views when a property in the document changes. Using the &lt;code&gt;@Published&lt;/code&gt; property wrapper for a property triggers updates to SwiftUI views when the property’s value changes. But the &lt;code&gt;@Published&lt;/code&gt; property wrapper works only for classes.&lt;/p&gt;&#xA;&lt;p&gt;If you are going to pass the document to many views, it can be more effective to make the document a class and use &lt;code&gt;@StateObject&lt;/code&gt;, &lt;code&gt;@ObservedObject&lt;/code&gt;, or &lt;code&gt;@EnvironmentObject&lt;/code&gt; to pass the document to other views.&lt;/p&gt;&#xA;&lt;p&gt;If you can’t mark the document as changed when using a struct, you can mark the document as changed by making the document a class and registering with the undo manager.&lt;/p&gt;&#xA;&lt;h3 id=&#34;changingthedocumentfromastructtoaclass&#34;&gt;Changing the Document from a Struct to a Class&lt;/h3&gt;&#xA;&lt;p&gt;Apple’s Swift file for the document creates a struct.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Document&lt;/span&gt;: FileDocument&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You must make the following changes to change the document from a struct to a class:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Change &lt;code&gt;struct&lt;/code&gt; to &lt;code&gt;class&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Change &lt;code&gt;FileDocument&lt;/code&gt; to &lt;code&gt;ReferenceFileDocument&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Have the document conform to &lt;code&gt;ObservableObject&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Document&lt;/span&gt;: ReferenceFileDocument, ObservableObject&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;creatingasnapshot&#34;&gt;Creating a Snapshot&lt;/h3&gt;&#xA;&lt;p&gt;You must add a &lt;code&gt;snapshot&lt;/code&gt; function to your document’s class to use &lt;code&gt;ReferenceFileDocument&lt;/code&gt;. The &lt;code&gt;snapshot&lt;/code&gt; function creates a snapshot of the document’s current state that SwiftUI uses to save the document.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;snapshot&lt;/span&gt;(contentType: UTType) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; GameScene {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.scene&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace &lt;code&gt;GameScene&lt;/code&gt; with the data type your document saves. Replace &lt;code&gt;scene&lt;/code&gt; with a property in your document class.&lt;/p&gt;&#xA;&lt;h3 id=&#34;markingthedocumentaschanged&#34;&gt;Marking the Document as Changed&lt;/h3&gt;&#xA;&lt;p&gt;If you find your document isn’t marked as changed when you make changes to the document, register your document with the undo manager by calling the &lt;code&gt;registerUndo&lt;/code&gt; function. Usually you call &lt;code&gt;registerUndo&lt;/code&gt; from a view’s &lt;code&gt;.onAppear&lt;/code&gt; modifier.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Add this property to the SwiftUI view.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Environment(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.undoManager) &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; undoManager&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.onAppear {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  undoManager?.registerUndo(withTarget: document, handler: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Use the handler to do anything your app&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// needs to do when registering the undo.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  print($0, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;undo&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;acknowledgements&#34;&gt;Acknowledgements&lt;/h3&gt;&#xA;&lt;p&gt;The answers to the following questions on Stack Overflow helped me write this article:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/64937346/what-is-the-difference-between-filedocument-and-referencefiledocument-for-d&#34;&gt;What is the difference between FileDocument and ReferenceFileDocument for DocumentGroups in SwiftUI?&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/63830923/swiftui-referencefiledocument-inability-to-indicate-a-document-needs-saving&#34;&gt;SwiftUI – ReferenceFileDocument – Inability to indicate a document needs saving&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Scene Editor Development: Unable to Open Scenes</title>
      <link>https://swiftdevjournal.com/scene-editor-development-unable-to-open-scenes/</link>
      <pubDate>Mon, 19 Jun 2023 18:40:56 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scene-editor-development-unable-to-open-scenes/</guid>
      <description>&lt;p&gt;I ran into a problem where I was unable to open the scenes I created in the editor. When I choose File &amp;gt; Open in the Mac version, the scene file is disabled. The scene file appears to save as the wrong type.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thedocumenttypeandutis&#34;&gt;The Document Type and UTIs&lt;/h3&gt;&#xA;&lt;p&gt;The scene editor saves scenes as binary property lists. I used the following identifier for the document type, imported UTI, and exported UTIs:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;com.apple.binary-property-list&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That identifier is the UTType for binary property lists.&lt;/p&gt;&#xA;&lt;p&gt;The type conforms to the following UTI:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;com.apple.property-list&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I set the file extension for the UTIs to &lt;code&gt;.sks&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;theproblem&#34;&gt;The Problem&lt;/h3&gt;&#xA;&lt;p&gt;When I saved a scene I got the following error message in Xcode’s console:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Error Domain=NSCocoaErrorDomain Code=256 “The autosaved document “TestScene” could not be reopened. SpriteKit Editor cannot open files in the “property list” format.”&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I also noticed the saved scene had the extension &lt;code&gt;.plist&lt;/code&gt; instead of &lt;code&gt;.sks&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thesolution&#34;&gt;The Solution&lt;/h3&gt;&#xA;&lt;p&gt;I created a custom identifier for the document type and UTIs. The document type conforms to the binary property list type, &lt;code&gt;com.apple.binary-property-list&lt;/code&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Scene Editor Development: Saving with NSKeyedArchiver</title>
      <link>https://swiftdevjournal.com/scene-editor-development-saving-with-nskeyedarchiver/</link>
      <pubDate>Tue, 30 May 2023 18:18:40 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scene-editor-development-saving-with-nskeyedarchiver/</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-trouble-conforming-to-codable/&#34;&gt;the last article&lt;/a&gt;, I wrote about how I couldn’t use the &lt;code&gt;PropertyListEncoder&lt;/code&gt; class to save scenes because SpriteKit’s classes don’t conform to the &lt;code&gt;Codable&lt;/code&gt; protocol. I have to use &lt;code&gt;NSKeyedArchiver&lt;/code&gt; to save the scenes, and that’s what I’m going to write about in this article.&lt;/p&gt;&#xA;&lt;h3 id=&#34;usingnskeyedarchiver&#34;&gt;Using NSKeyedArchiver&lt;/h3&gt;&#xA;&lt;p&gt;Archiving data with &lt;code&gt;NSKeyedArchiver&lt;/code&gt; requires one function call. Call the class function &lt;code&gt;archivedData&lt;/code&gt;. Supply a root object and whether or not the archive requires secure coding. You should set the second argument to true. I used the following initial code to archive a scene:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sceneData = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; NSKeyedArchiver.archivedData(withRootObject:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  GameScene.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;, requiringSecureCoding: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Calling the &lt;code&gt;archivedData&lt;/code&gt; function is enough in most cases. But I also had to say that my &lt;code&gt;SKScene&lt;/code&gt; subclass supports secure coding.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; supportsSecureCoding: Bool {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;problem1:unrecognizedselectorerror&#34;&gt;Problem 1: Unrecognized Selector Error&lt;/h3&gt;&#xA;&lt;p&gt;When I saved the scene, the app would crash with the following error message in Xcode’s console:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;+[SpriteKit_Editor.GameScene encodeWithCoder:]: unrecognized selector sent to class 0x10cb6aa60&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The error message is saying that my &lt;code&gt;GameScene&lt;/code&gt; class does not have an &lt;code&gt;encodeWithCoder&lt;/code&gt; function. The cause of the error is I was passing my &lt;code&gt;SKScene&lt;/code&gt; class as the root object instead of the scene itself. Passing the scene as the root object fixed the error.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sceneData = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; NSKeyedArchiver.archivedData(withRootObject:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scene, requiringSecureCoding: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;problem2:rootobjecthasthewrongclass&#34;&gt;Problem 2: Root Object Has the Wrong Class&lt;/h3&gt;&#xA;&lt;p&gt;I wanted to see if I could load a scene I saved in a SpriteKit game project. I created a test project in Xcode, added a scene I created in the editor, and tried to load the scene with the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;currentScene = SKScene(fileNamed: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TestGameScene&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The app crashed with the following error message in Xcode’s console:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Terminating app due to uncaught exception ‘NSInvalidUnarchiveOperationException’, reason: ‘*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (SpriteKit_Editor.GameScene) for key (root) because no class named “SpriteKit_Editor.GameScene” was found; the class needs to be defined in source code or linked in from a library (ensure the class is part of the correct target). If the class was renamed, use setClassName:forClass: to add a class translation mapping to NSKeyedUnarchiver’&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The error message says the type of the root object in the archive is the &lt;code&gt;SKScene&lt;/code&gt; subclass in the scene editor app when it needs to be &lt;code&gt;SKScene&lt;/code&gt;. I have to archive the scene as type &lt;code&gt;SKScene&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;My first attempt was to cast the scene as type &lt;code&gt;SKScene&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sceneData = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; NSKeyedArchiver.archivedData(withRootObject: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scene &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; SKScene, requiringSecureCoding: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But I got the same crash when trying to load the scene in a SpriteKit project.&lt;/p&gt;&#xA;&lt;p&gt;My second attempt was to create a &lt;code&gt;SKScene&lt;/code&gt; variable and archive that variable.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; skScene: SKScene = scene&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sceneData = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; NSKeyedArchiver.archivedData(withRootObject: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  skScene, requiringSecureCoding: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That did not fix the error.&lt;/p&gt;&#xA;&lt;p&gt;The solution is to call the &lt;code&gt;setClassName&lt;/code&gt; function to tell the archiver to save the scene as type &lt;code&gt;SKScene&lt;/code&gt;. The following code saves the scene correctly:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fileWrapper&lt;/span&gt;(configuration: WriteConfiguration) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; FileWrapper {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  NSKeyedArchiver.setClassName(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SKScene&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;: GameScene.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sceneData = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; NSKeyedArchiver.archivedData(withRootObject: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#x9;scene, requiringSecureCoding: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; .&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(regularFileWithContents: sceneData)        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;pleasantsurprise:bbeditcanshowbinarypropertylists&#34;&gt;Pleasant Surprise: BBEdit Can Show Binary Property Lists&lt;/h3&gt;&#xA;&lt;p&gt;I learned that the text editor BBEdit shows binary property lists as XML files. Now I don’t have to worry about being unable to examine the contents of the scene. I can save the scenes as binary property lists and view them in BBEdit. I can also view the scene in Xcode as a SpriteKit scene.&lt;/p&gt;&#xA;&lt;h3 id=&#34;unarchivingthescene&#34;&gt;Unarchiving the Scene&lt;/h3&gt;&#xA;&lt;p&gt;To open scenes in the scene editor, I have to add support for unarchiving the data. To support unarchiving I use the &lt;code&gt;NSKeyedUnarchiver&lt;/code&gt; class. I have to set the class name to treat the &lt;code&gt;SKScene&lt;/code&gt; root object as an object of my subclass. The last step is to call the &lt;code&gt;unarchivedObject&lt;/code&gt; function to read the archived data and create an instance of my subclass from the data. The following code loads the scene document:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(configuration: ReadConfiguration) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; data = configuration.file.regularFileContents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; CocoaError(.fileReadCorruptFile)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  NSKeyedUnarchiver.setClass(GameScene.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;, forClassName: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SKScene&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scene = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; NSKeyedUnarchiver.unarchivedObject(ofClass: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    GameScene.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;, from: data) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ?? GameScene(size: CGSize(width: &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt;, height: &lt;span style=&#34;color:#ae81ff&#34;&gt;1536&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Scene Editor Development: Trouble Conforming to Codable</title>
      <link>https://swiftdevjournal.com/scene-editor-development-trouble-conforming-to-codable/</link>
      <pubDate>Mon, 22 May 2023 17:32:39 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scene-editor-development-trouble-conforming-to-codable/</guid>
      <description>&lt;p&gt;For a SpriteKit scene editor to be usable, it must be able to save scenes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;choosingafileformat&#34;&gt;Choosing a File Format&lt;/h3&gt;&#xA;&lt;p&gt;SpriteKit scene files are binary property lists with the extension &lt;code&gt;.sks&lt;/code&gt;. At the very least the scene editor must be able to export scenes as binary property lists.&lt;/p&gt;&#xA;&lt;p&gt;During development I would like to view a saved scene’s data in a text editor to make sure everything saves correctly. The Foundation framework supports saving property lists as XML or binary so I decided to save the scenes as property lists. Start by saving as XML and switch to binary later in development.&lt;/p&gt;&#xA;&lt;h3 id=&#34;propertylistencoder&#34;&gt;PropertyListEncoder&lt;/h3&gt;&#xA;&lt;p&gt;Looking through Apple’s documentation I saw the Foundation framework has &lt;code&gt;PropertyListEncoder&lt;/code&gt; and &lt;code&gt;PropertyListDecoder&lt;/code&gt; classes to save and load property list files. I wrote the following code to save a scene:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fileWrapper&lt;/span&gt;(configuration: WriteConfiguration) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; FileWrapper {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; propertyListEncoder = PropertyListEncoder()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  propertyListEncoder.outputFormat = .xml&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sceneData = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; propertyListEncoder.encode(scene)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; .&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(regularFileWithContents: sceneData)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Saving to a property list requires only three lines of code. Create an instance of &lt;code&gt;PropertyListEncoder&lt;/code&gt;, set the output format, and call the &lt;code&gt;encode&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;p&gt;If you need to save data in a property list in your app, start by using &lt;code&gt;PropertyListEncoder&lt;/code&gt;. But I ran into problems when I tried to use &lt;code&gt;PropertyListEncoder&lt;/code&gt; in the scene editor.&lt;/p&gt;&#xA;&lt;h3 id=&#34;spritekitclassesdontconformtocodable&#34;&gt;SpriteKit Classes Don’t Conform to Codable&lt;/h3&gt;&#xA;&lt;p&gt;To encode data with &lt;code&gt;PropertyListEncoder&lt;/code&gt;, the data you are encoding must conform to the &lt;code&gt;Codable&lt;/code&gt; protocol. SpriteKit classes don’t conform to &lt;code&gt;Codable&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I searched online to see if there was a way to make SpriteKit classes conform to &lt;code&gt;Codable&lt;/code&gt;. To make a struct or class conform to &lt;code&gt;Codable&lt;/code&gt;, the struct or class must implement the following functions:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;required&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(from decoder: Decoder) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;encode&lt;/span&gt;(to encoder: Encoder) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I tried creating a class extension file for the &lt;code&gt;SKScene&lt;/code&gt; class and learned I cannot add a required initializer in a class extension file. Since I don’t have access to the source code files for Apple’s SpriteKit framework, I can’t make SpriteKit classes conform to &lt;code&gt;Codable&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;usenskeyedarchivertosavescenedata&#34;&gt;Use NSKeyedArchiver to Save Scene Data&lt;/h3&gt;&#xA;&lt;p&gt;Because SpriteKit classes don’t conform to &lt;code&gt;Codable&lt;/code&gt;, I can’t use &lt;code&gt;PropertyListEncoder&lt;/code&gt; to save scenes as property lists. I have to use &lt;code&gt;NSKeyedArchiver&lt;/code&gt;. I will cover using &lt;code&gt;NSKeyedArchiver&lt;/code&gt; in the next article.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-saving-with-nskeyedarchiver/&#34;&gt;Scene Editor Development: Saving with NSKeyedArchiver&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Scene Editor Development: SwiftUI Navigation Issues</title>
      <link>https://swiftdevjournal.com/scene-editor-development-swiftui-navigation-issues/</link>
      <pubDate>Mon, 15 May 2023 17:49:30 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scene-editor-development-swiftui-navigation-issues/</guid>
      <description>&lt;p&gt;I have the following main view in the scene:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContentView&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: Level&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    NavigationView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      SceneGraph(document: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      SpriteView(scene: document.scene)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Inspector(node: SKNode())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When selecting an item from the scene graph, I want to show the details in the inspector. I created a navigation link to do this.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ForEach(gameScene.children, id: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { node &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    NavigationLink(destination: Inspector(node: node), tag: node, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      selection: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;selection) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Text(node.name ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Node&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problem is that when I select an item from the scene graph, the inspector replaces the sprite view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;navigationsplitview&#34;&gt;NavigationSplitView&lt;/h3&gt;&#xA;&lt;p&gt;I took a look at the new &lt;code&gt;NavigationSplitView&lt;/code&gt; view Apple added in iOS 16 and macOS 13 to handle the navigation. But I found the three column view doesn’t suit this app.&lt;/p&gt;&#xA;&lt;p&gt;The behavior of a three column split view is that selecting an item from the first column affects the second column, and selecting an item from the second column affects the third column.&lt;/p&gt;&#xA;&lt;p&gt;But I don’t want someone to have to select an item from the sprite view (scene canvas) to view it in the inspector. Selecting an item from the scene graph should show the details in the inspector.&lt;/p&gt;&#xA;&lt;h3 id=&#34;workaround&#34;&gt;Workaround&lt;/h3&gt;&#xA;&lt;p&gt;The workaround is to move the sprite view from the center column to the left column. Now the navigation link from the scene graph to the inspector works the way I want it to work.&lt;/p&gt;&#xA;&lt;p&gt;For now I’m sticking with &lt;code&gt;NavigationView&lt;/code&gt; to support iOS 15, which has a version of Swift Playgrounds that can make apps. It also allows me to support macOS 11+. But I may switch to a two column navigation split view if I need it.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Scene Editor Development: Updating a SwiftUI List When Adding an Item</title>
      <link>https://swiftdevjournal.com/scene-editor-development-updating-the-scene-graph-when-adding-an-item-to-the-scene/</link>
      <pubDate>Mon, 08 May 2023 17:28:57 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scene-editor-development-updating-the-scene-graph-when-adding-an-item-to-the-scene/</guid>
      <description>&lt;p&gt;This article talks about the first big problem I encountered when starting to develop a SpriteKit scene editor in SwiftUI. It’s a problem every SwiftUI developer has seen: a view doesn’t update when the data changes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;initialcode&#34;&gt;Initial Code&lt;/h3&gt;&#xA;&lt;p&gt;My initial idea for the scene editor interface was to have a split view with three columns.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A scene graph to show the items in the scene&lt;/li&gt;&#xA;&lt;li&gt;A canvas to place items in the scene&lt;/li&gt;&#xA;&lt;li&gt;An inspector to view and edit details for an item&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I started with the following SwiftUI view:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContentView&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: Level&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    NavigationView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      SceneGraph(document: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;SpriteView(scene: document.scene)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Inspector()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I used a SwiftUI sprite view for the canvas.&lt;/p&gt;&#xA;&lt;p&gt;The document struct has a property that holds a SpriteKit scene.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Level&lt;/span&gt;: FileDocument {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; scene: GameScene&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;GameScene&lt;/code&gt; is a subclass of &lt;code&gt;SKScene&lt;/code&gt;, SpriteKit’s scene class.&lt;/p&gt;&#xA;&lt;p&gt;The scene graph looks like the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SceneGraph&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: Level&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    List {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ForEach(document.scene.children, id: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { item &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Text(item.name ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Node&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;myinitialgoal&#34;&gt;My Initial Goal&lt;/h3&gt;&#xA;&lt;p&gt;My initial goal was to add a sprite to the scene by clicking or tapping on the canvas. The sprite’s location is the location of the click or tap. Adding the sprite also adds an item to the scene graph.&lt;/p&gt;&#xA;&lt;h3 id=&#34;problem:theswiftuilistdoesntupdatewhenaddinganitem&#34;&gt;Problem: The SwiftUI List Doesn’t Update when Adding an Item&lt;/h3&gt;&#xA;&lt;p&gt;I ran the app and tried adding sprites to the canvas. The sprites appeared on the canvas, but the scene graph was empty.&lt;/p&gt;&#xA;&lt;p&gt;I stepped through the code in the debugger and saw that the new sprites were in the scene’s array of children. When I saved the document the sprites appeared in the scene graph.&lt;/p&gt;&#xA;&lt;p&gt;Adding sprites works, but the scene graph doesn’t update. This is a common problem SwiftUI developers run into. The user interface doesn’t update when the data changes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;fixattemptsthatdidntwork&#34;&gt;Fix Attempts that Didn’t Work&lt;/h3&gt;&#xA;&lt;p&gt;There are two common approaches to get the user interface to update when the data changes. First, if your data model uses structs, use &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@Binding&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Second, if your data model uses classes, make the class conform to &lt;code&gt;ObservableObject&lt;/code&gt;. Add the &lt;code&gt;@Published&lt;/code&gt; property wrapper to class members that you want to trigger a UI update when the member’s value changes.&lt;/p&gt;&#xA;&lt;p&gt;I tried the following things to get the scene graph to update when adding a sprite to the scene:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Make &lt;code&gt;GameScene&lt;/code&gt; conform to &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Add a &lt;code&gt;@Published&lt;/code&gt; variable to &lt;code&gt;GameScene&lt;/code&gt; that holds an array of the scene’s items, have &lt;code&gt;GameScene&lt;/code&gt; conform to &lt;code&gt;ObservableObject&lt;/code&gt;, and have the scene graph show the array of scene items.&lt;/li&gt;&#xA;&lt;li&gt;Make &lt;code&gt;Level&lt;/code&gt; a class with a &lt;code&gt;@Published&lt;/code&gt; property for the scene and use &lt;code&gt;@StateObject&lt;/code&gt; instead of &lt;code&gt;@Binding&lt;/code&gt; in the scene graph.&lt;/li&gt;&#xA;&lt;li&gt;Add a &lt;code&gt;@Published&lt;/code&gt; variable that tracks whether the scene was edited and set it to true when placing the sprite.&lt;/li&gt;&#xA;&lt;li&gt;Add a refresh ID to the &lt;code&gt;GameScene&lt;/code&gt; class and change it when placing the sprite.&lt;/li&gt;&#xA;&lt;li&gt;Add a refresh ID to the &lt;code&gt;Level&lt;/code&gt; struct and change it when clicking on the canvas.&lt;/li&gt;&#xA;&lt;li&gt;Add a property for the level to the &lt;code&gt;GameScene&lt;/code&gt;class.&lt;/li&gt;&#xA;&lt;li&gt;Give the scene graph a binding to a game scene instead of a level.&lt;/li&gt;&#xA;&lt;li&gt;Give the scene graph a &lt;code&gt;@StateObject&lt;/code&gt; property for the scene.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;None of these attempts updated the scene graph after adding a sprite to the canvas.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thesolution&#34;&gt;The Solution&lt;/h3&gt;&#xA;&lt;p&gt;I struggled to fix this problem for weeks. Finally &lt;a href=&#34;https://www.reddit.com/r/SwiftUI/comments/11m6yfv/getting_a_swiftui_view_to_update_when_a_spritekit/&#34;&gt;I asked a question on Reddit about the problem&lt;/a&gt; and learned what the problem was. The problem has two parts.&lt;/p&gt;&#xA;&lt;p&gt;First, SwiftUI’s data flow system does not automatically track changes in SpriteKit scenes. I have to manually trigger changes when the scene changes.&lt;/p&gt;&#xA;&lt;p&gt;Second, The binding for the level in the scene graph won’t trigger an update unless I make the level show a new scene. The app is a scene editor so I am never going to change the scene in a level. Because I don’t change scenes in a level, any changes I make to the level will not trigger a UI update.&lt;/p&gt;&#xA;&lt;p&gt;The solution to the problem has the following parts:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Make &lt;code&gt;GameScene&lt;/code&gt; conform to &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Send an &lt;code&gt;objectWillChange&lt;/code&gt; message after placing the sprite.&lt;/li&gt;&#xA;&lt;li&gt;Add a private property for the scene to the scene graph with the &lt;code&gt;@ObservedObject&lt;/code&gt; property wrapper.&lt;/li&gt;&#xA;&lt;li&gt;Add a private property for the level.&lt;/li&gt;&#xA;&lt;li&gt;Use the private property for the scene in the &lt;code&gt;ForEach&lt;/code&gt; block.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Sending the &lt;code&gt;objectWillChange&lt;/code&gt; message required adding one line of code.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.objectWillChange.send()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I had to add the following code to the &lt;code&gt;SceneGraph&lt;/code&gt; struct:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: Level&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@ObservedObject &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; gameScene: GameScene&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(document: Level) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.document = document&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.gameScene = document.scene&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The final thing I had to do was change the code of the &lt;code&gt;ForEach&lt;/code&gt; block for the list to the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ForEach(gameScene.children, id: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { item &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(item.name ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Node&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>SwiftUI Open and Save Panels</title>
      <link>https://swiftdevjournal.com/swiftui-open-and-save-panels/</link>
      <pubDate>Thu, 04 May 2023 17:56:29 +0000</pubDate>
      <guid>https://swiftdevjournal.com/swiftui-open-and-save-panels/</guid>
      <description>&lt;p&gt;AppKit has the &lt;code&gt;NSOpenPanel&lt;/code&gt; and &lt;code&gt;NSSavePanel&lt;/code&gt; classes to let people choose files to open and save in Mac apps. What is the SwiftUI equivalent to &lt;code&gt;NSOpenPanel&lt;/code&gt; and &lt;code&gt;NSSavePanel&lt;/code&gt;?&lt;/p&gt;&#xA;&lt;p&gt;SwiftUI has &lt;code&gt;.fileImporter&lt;/code&gt; and &lt;code&gt;.fileExporter&lt;/code&gt; modifiers to let people choose files to open and save. Apply the modifier to a SwiftUI view, such as a button or a menu item. The &lt;code&gt;.fileImporter&lt;/code&gt; and &lt;code&gt;.fileExporter&lt;/code&gt; modifiers are available on both iOS and Mac.&lt;/p&gt;&#xA;&lt;h3 id=&#34;fileimporters&#34;&gt;File Importers&lt;/h3&gt;&#xA;&lt;p&gt;You must provide the following to &lt;code&gt;.fileImporter&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A Boolean value that determines whether or not to show the panel&lt;/li&gt;&#xA;&lt;li&gt;A list of allowed file types to open&lt;/li&gt;&#xA;&lt;li&gt;A completion handler that runs when the panel closes&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The following code lets someone open an image file:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; isImporting: Bool = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  isImporting = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Import Image&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.fileImporter(isPresented: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;isImporting, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  allowedContentTypes: [.png, .jpeg, .tiff], &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  onCompletion: { result &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; result {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .success(&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; url):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// url contains the URL of the chosen file.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; newImage = createImage(imageFile: url)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .failure(&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; error):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the person chooses a file and clicks the Open button, the result is &lt;code&gt;.success&lt;/code&gt;, and the file importer provides the URL of the chosen file for you.&lt;/p&gt;&#xA;&lt;h3 id=&#34;fileexporters&#34;&gt;File Exporters&lt;/h3&gt;&#xA;&lt;p&gt;You must provide the following to &lt;code&gt;.fileExporter&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A Boolean value that determines whether or not to show the panel&lt;/li&gt;&#xA;&lt;li&gt;The document to export&lt;/li&gt;&#xA;&lt;li&gt;The file type for the exported file&lt;/li&gt;&#xA;&lt;li&gt;A completion handler that runs when the panel closes&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;You can also supply a default file name to the file exporter.&lt;/p&gt;&#xA;&lt;p&gt;The following code exports a document to EPUB:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; isPublishing: Bool = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  isPublishing = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Publish&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.fileExporter(isPresented: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;isPublishing,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  document: book,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  contentType: .epub,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  defaultFilename: book.title) { result &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; result {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .success(&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; url):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    book.publishEPUB(location: url)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .failure(&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; error):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the person chooses a location to save the file and clicks the Export button, the result is &lt;code&gt;.success&lt;/code&gt;, and the file exporter provides the URL of the chosen file for you to write data from your app to the file.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Scene Editor Development: Intro</title>
      <link>https://swiftdevjournal.com/scene-editor-development-intro/</link>
      <pubDate>Mon, 01 May 2023 17:53:45 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scene-editor-development-intro/</guid>
      <description>&lt;p&gt;As a fun side project, I’m starting to develop a SpriteKit scene editor for iPad and Mac using SwiftUI. I decided to write about the development of this project.&lt;/p&gt;&#xA;&lt;p&gt;This post is the first in a series of posts. Future posts will be more technical than this one.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whymakeaspritekitsceneeditor&#34;&gt;Why Make a SpriteKit Scene Editor?&lt;/h3&gt;&#xA;&lt;p&gt;Doesn’t Xcode include a SpriteKit scene editor? Yes it does.&lt;/p&gt;&#xA;&lt;p&gt;So why make a SpriteKit scene editor?&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://apps.apple.com/us/app/swift-playgrounds/id908519492&#34;&gt;Swift Playgrounds app&lt;/a&gt; lets people &lt;a href=&#34;https://www.checksimgames.com/using-spritekit-in-the-swift-playgrounds-app/&#34;&gt;make SpriteKit games on an iPad&lt;/a&gt;. Use a SwiftUI sprite view to display a SpriteKit scene, and you can make a 2D game on an iPad.&lt;/p&gt;&#xA;&lt;p&gt;Swift Playgrounds does not include a scene editor so you must build your scenes in code if you have only an iPad. By making a scene editor people on an iPad can create scenes for a game visually.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatwilliwriteabout&#34;&gt;What Will I Write About?&lt;/h3&gt;&#xA;&lt;p&gt;Most of the time I’ll be writing about a problem I faced and how I solved it. I think that will interest the most people, solving problems in SwiftUI apps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wherecanidownloadtheeditor&#34;&gt;Where Can I Download the Editor?&lt;/h3&gt;&#xA;&lt;p&gt;The editor currently isn’t available to download because it’s not usable. Right now I’m in a prototyping stage to see what I can do with SwiftUI. I would also like to find a good name for the editor before I release an early version.&lt;/p&gt;&#xA;&lt;p&gt;When I have the editor ready for others to use, I’ll make it available to download.&lt;/p&gt;&#xA;&lt;p&gt;Keep in mind that progress may be slow at times. This is a side project that does things that not many SwiftUI apps do. Doing unusual things makes finding solutions to problems more difficult because people haven’t written articles or asked questions about them.&lt;/p&gt;&#xA;&lt;h3 id=&#34;sceneeditordevelopmentarticlelist&#34;&gt;Scene Editor Development Article List&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-intro/&#34;&gt;Intro&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scrolling-a-swiftui-sprite-view/&#34;&gt;Scrolling a SwiftUI Sprite View&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-updating-the-scene-graph-when-adding-an-item-to-the-scene/&#34;&gt;Updating a SwiftUI List When Adding an Item&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-swiftui-navigation-issues/&#34;&gt;SwiftUI Navigation Issues&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-trouble-conforming-to-codable/&#34;&gt;Trouble Conforming to Codable&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-saving-with-nskeyedarchiver/&#34;&gt;Saving with NSKeyedArchiver&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-unable-to-open-scenes/&#34;&gt;Unable to Open Scenes&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/scene-editor-development-showing-a-swiftui-view-based-on-a-selection/&#34;&gt;Showing a SwiftUI View Based on a Selection&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Working on a SwiftUI Project in Xcode and Swift Playgrounds</title>
      <link>https://swiftdevjournal.com/working-on-a-swiftui-project-in-xcode-and-swift-playgrounds/</link>
      <pubDate>Fri, 14 Apr 2023 18:39:30 +0000</pubDate>
      <guid>https://swiftdevjournal.com/working-on-a-swiftui-project-in-xcode-and-swift-playgrounds/</guid>
      <description>&lt;p&gt;You have a Mac with Xcode and an iPad with Swift Playgrounds. You have a project that you want to develop using both devices. How do you create a project that you can edit in both Xcode and Swift Playgrounds?&lt;/p&gt;&#xA;&lt;p&gt;Create a Swift Playgrounds App project in Xcode. This project template is designed to work in both Xcode and Swift Playgrounds.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ChooseSwiftPlaygroundsAppProject.png&#34; alt=&#34;choose Swift Playgrounds app project&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The Swift Playgrounds App project is in the iOS section of the New Project Assistant in Xcode.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Scrolling a SwiftUI Sprite View</title>
      <link>https://swiftdevjournal.com/scrolling-a-swiftui-sprite-view/</link>
      <pubDate>Thu, 30 Mar 2023 18:38:43 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scrolling-a-swiftui-sprite-view/</guid>
      <description>&lt;p&gt;SwiftUI provides a sprite view to show a SpriteKit scene in a SwiftUI app. Supply a SpriteKit scene to the sprite view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContentView&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; currentScene: SKScene = GameScene(size: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CGSize(width: &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt;, height: &lt;span style=&#34;color:#ae81ff&#34;&gt;1536&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    SpriteView(scene: currentScene)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SwiftUI provides a scroll view to scroll content that won’t fit in the main SwiftUI view. Place the sprite view inside the scroll view to scroll the scene.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ScrollView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    SpriteView(scene: currentScene)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you build and run this code, you will notice the scroll view covers the sprite view so you can’t see the sprite view or interact with it. How do you keep the scroll view from blocking the sprite view?&lt;/p&gt;&#xA;&lt;p&gt;Add a &lt;code&gt;.frame&lt;/code&gt; modifier to the sprite view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ScrollView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    SpriteView(scene: currentScene)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      .frame(width: &lt;span style=&#34;color:#ae81ff&#34;&gt;768&lt;/span&gt;, height: &lt;span style=&#34;color:#ae81ff&#34;&gt;768&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to scroll the scene horizontally and vertically, supply the scrolling directions in an array when creating the scroll view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ScrollView([.horizontal, .vertical]) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    SpriteView(scene: currentScene)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      .frame(width: &lt;span style=&#34;color:#ae81ff&#34;&gt;768&lt;/span&gt;, height: &lt;span style=&#34;color:#ae81ff&#34;&gt;768&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Using a UIKit or AppKIt View in SwiftUI</title>
      <link>https://swiftdevjournal.com/using-a-uikit-or-appkit-view-in-swiftui/</link>
      <pubDate>Mon, 20 Feb 2023 18:48:41 +0000</pubDate>
      <guid>https://swiftdevjournal.com/using-a-uikit-or-appkit-view-in-swiftui/</guid>
      <description>&lt;h3 id=&#34;whentowrapauikitorappkitview&#34;&gt;When to Wrap a UIKit or AppKit View&lt;/h3&gt;&#xA;&lt;p&gt;There are two cases where you would wrap a UIKit or AppKit view in a SwiftUI app. The first case is your app needs a view that SwiftUI doesn’t have. If your app needs to show web content or a PDF file, you must use a WebKit web view or PDFKit’s PDF view. SwiftUI currently doesn’t have a native web view or PDF view.&lt;/p&gt;&#xA;&lt;p&gt;The second case is your app needs to do something that a SwiftUI view can’t do. To let people edit rich text in your app, you must use &lt;code&gt;UITextView&lt;/code&gt; or &lt;code&gt;NSTextView&lt;/code&gt;. SwiftUI’s &lt;code&gt;TextEditor&lt;/code&gt; view only allows plain text editing. Text views are a common control where you have to drop down to UIKit or AppKit because SwiftUI’s text editor is very limited currently.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wrappingauikitorappkitview&#34;&gt;Wrapping a UIKit or AppKit View&lt;/h3&gt;&#xA;&lt;p&gt;To wrap a UIKIt or AppKit view in a SwiftUI app, perform the following steps:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a struct that conforms to the &lt;code&gt;UIViewRepresentable&lt;/code&gt;(iOS) or &lt;code&gt;NSViewRepresentable&lt;/code&gt;(Mac) protocols.&lt;/li&gt;&#xA;&lt;li&gt;Write a &lt;code&gt;makeUIView&lt;/code&gt; or &lt;code&gt;makeNSView&lt;/code&gt; function to create the UIKit or AppKit view.&lt;/li&gt;&#xA;&lt;li&gt;Write an &lt;code&gt;updateUIView&lt;/code&gt; or &lt;code&gt;updateNSView&lt;/code&gt; function to handle view updates.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The following code creates a web view that displays HTML text:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WebKit&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SwiftUI&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WebView&lt;/span&gt;: UIViewRepresentable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; html: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(html: String) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.html = html&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeUIView&lt;/span&gt;(context: Context) -&amp;gt; WKWebView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; webView = WKWebView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; webView&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateUIView&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; uiView: WKWebView, context: Context) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    uiView.loadHTMLString(html, baseURL: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that &lt;code&gt;makeUIView&lt;/code&gt; returns the view type. The view type is also the type of the first argument to &lt;code&gt;updateUIView&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;After creating the view struct, you can add the view as part of the body of a SwiftUI view the same way you would add one of SwiftUI’s native views.&lt;/p&gt;&#xA;&lt;h3 id=&#34;examplesandfurtherreading&#34;&gt;Examples and Further Reading&lt;/h3&gt;&#xA;&lt;p&gt;I have a &lt;a href=&#34;https://github.com/SwiftDevJournal/WikiDemo&#34;&gt;demo project on GitHub&lt;/a&gt; that wraps a web view in a multi-platform SwiftUI app.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://github.com/ZeeZide/CodeEditor&#34;&gt;CodeEditor package&lt;/a&gt; wraps a text view that supports syntax highlighting. It’s a more complex example than my demo project.&lt;/p&gt;&#xA;&lt;p&gt;The following articles have additional information on using UIKit and AppKit views in SwiftUI:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/using-text-views-in-a-swiftui-app/&#34;&gt;Using Text Views in a SwiftUI App&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/using-a-scrollable-text-view-in-a-mac-swiftui-app/&#34;&gt;Using a Scrollable Text View in a Mac SwiftUI App&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Storing a Swift Enum in Core Data</title>
      <link>https://swiftdevjournal.com/storing-a-swift-enum-in-core-data/</link>
      <pubDate>Mon, 13 Feb 2023 19:01:42 +0000</pubDate>
      <guid>https://swiftdevjournal.com/storing-a-swift-enum-in-core-data/</guid>
      <description>&lt;p&gt;You must do the following to store a Swift enum in Core Data:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create an enum with a raw value with a type Core Data can store, such as an integer or a string.&lt;/li&gt;&#xA;&lt;li&gt;Add an attribute for the enum to the Core Data entity. Set the attribute’s type to the raw value type.&lt;/li&gt;&#xA;&lt;li&gt;Add a computed property to the entity to convert the enum to and from the attribute’s raw value.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;creatingtheenum&#34;&gt;Creating the Enum&lt;/h3&gt;&#xA;&lt;p&gt;Core Data has no way of knowing your enum. That’s why you must give your enum a raw value type. Supplying a raw value type lets Core Data store the enum value.&lt;/p&gt;&#xA;&lt;p&gt;The following code shows an enum for issue priorities whose raw value type is an integer:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IssuePriority&lt;/span&gt;: Int {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; low = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; medium = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; high = &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Core Data will save the integer values of the issue priorities.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addingthecomputedproperty&#34;&gt;Adding the Computed Property&lt;/h3&gt;&#xA;&lt;p&gt;Adding a computed property to the Core Data entity allows you to use the Swift enum in your code. The usual way to add a computed property is to create an extension for the Core Data entity type.&lt;/p&gt;&#xA;&lt;p&gt;The computed property requires a getter and a setter. The getter creates an enum value from its raw value. The setter sets the raw value for the enum value.&lt;/p&gt;&#xA;&lt;p&gt;The next example shows an &lt;code&gt;Issue&lt;/code&gt; entity with a &lt;code&gt;priorityLevel&lt;/code&gt; attribute of type &lt;code&gt;Int64&lt;/code&gt;. The following code creates a computed property for the issue priority:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Issue&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; priority: IssuePriority {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; IssuePriority(rawValue: Int(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.priorityLevel)) ?? .low&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.priorityLevel = Int64(newValue.rawValue)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now you can use the &lt;code&gt;priority&lt;/code&gt; property to set issue priorities using the enum values.&lt;/p&gt;&#xA;&lt;p&gt;When writing the setter make sure to use the same data type as the attribute in the Core Data model, &lt;code&gt;Int64&lt;/code&gt; in the example.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Fixing the Type () cannot conform to View Error in Swift</title>
      <link>https://swiftdevjournal.com/fixing-the-type-cannot-conform-to-view-error-in-swift/</link>
      <pubDate>Mon, 23 Jan 2023 18:18:39 +0000</pubDate>
      <guid>https://swiftdevjournal.com/fixing-the-type-cannot-conform-to-view-error-in-swift/</guid>
      <description>&lt;h3 id=&#34;whyamigettingthiserror&#34;&gt;Why am I getting this error?&lt;/h3&gt;&#xA;&lt;p&gt;You are trying to do something inside the body of a SwiftUI view besides displaying views. Placing &lt;code&gt;print&lt;/code&gt; statements in a SwiftUI view will give you this error. Using &lt;code&gt;if&lt;/code&gt; statements to conditionally show a view may also generate this error.&lt;/p&gt;&#xA;&lt;p&gt;Let’s look at a simple example that shows a name in a SwiftUI Text label.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContentView&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; name: String = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    name = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Angela&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Text(name)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code in the example is trying to set the name to show inside the &lt;code&gt;body&lt;/code&gt; computed property. But you can’t run arbitrary code, such as setting a variable’s value, inside the &lt;code&gt;body&lt;/code&gt; property. The &lt;code&gt;body&lt;/code&gt; property must return a SwiftUI view so the code generates the &lt;strong&gt;Type () cannot conform to View&lt;/strong&gt; error.&lt;/p&gt;&#xA;&lt;h3 id=&#34;waystofixtheerror&#34;&gt;Ways to fix the error&lt;/h3&gt;&#xA;&lt;p&gt;The easiest way to fix the error in the example is to set the name when creating the &lt;code&gt;name&lt;/code&gt; variable.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; name: String = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Angela&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(name)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the &lt;code&gt;.onAppear&lt;/code&gt; modifier to do something when a SwiftUI view appears. The following code changes the name correctly:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View { &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(name)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .onAppear {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      name = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Angela&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also make the error go away by adding a &lt;code&gt;return&lt;/code&gt; statement to explicitly return a view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  name = &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;“&lt;/span&gt;Angela&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;”&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Text(name)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Remove &lt;code&gt;print&lt;/code&gt; statements from your SwiftUI views. If you need to print something to debug your app, &lt;a href=&#34;https://www.swiftdevjournal.com/replace-swift-print-statements-with-xcode-breakpoint-actions/&#34;&gt;use Xcode breakpoint actions to print to Xcode’s console&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;If you need to do something in a SwiftUI view, move the code out of the &lt;code&gt;body&lt;/code&gt; property to a separate function and call the function in the view.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Fixing the Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value error</title>
      <link>https://swiftdevjournal.com/fixing-the-thread-1-fatal-error-unexpectedly-found-nil-while-implicitly-unwrapping-an-optional-value-error/</link>
      <pubDate>Tue, 17 Jan 2023 18:49:30 +0000</pubDate>
      <guid>https://swiftdevjournal.com/fixing-the-thread-1-fatal-error-unexpectedly-found-nil-while-implicitly-unwrapping-an-optional-value-error/</guid>
      <description>&lt;h3 id=&#34;whyamigettingthiserror&#34;&gt;Why am I getting this error?&lt;/h3&gt;&#xA;&lt;p&gt;You are getting this error because you are doing something with an optional value that is nil. The most common reasons for doing something with a nil optional value are the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;You have an implicitly unwrapped optional&lt;/li&gt;&#xA;&lt;li&gt;You have a disconnected outlet in a storyboard&lt;/li&gt;&#xA;&lt;li&gt;You force unwrap an optional&lt;/li&gt;&#xA;&lt;li&gt;You use &lt;code&gt;as!&lt;/code&gt; to cast to a data type&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Storyboard outlets are the most common use of implicitly unwrapped optionals.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DisconnectedOutletHighlighted.png&#34; alt=&#34;disconnected outlet&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;textView&lt;/code&gt; outlet has type &lt;code&gt;UITextView!&lt;/code&gt;. Adding the &lt;code&gt;!&lt;/code&gt; character makes the outlet an implicitly unwrapped optional. A disconnected outlet has an empty circle in Xcode’s source code editor, as you can see in the image. Accessing a disconnected outlet crashes your app.&lt;/p&gt;&#xA;&lt;h4 id=&#34;forceunwrappingexample&#34;&gt;Force Unwrapping Example&lt;/h4&gt;&#xA;&lt;p&gt;The following code demonstrates force unwrapping by getting the contents of a file wrapper:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; data = file.regularFileContents!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Adding the &lt;code&gt;!&lt;/code&gt; after &lt;code&gt;regularFileContents&lt;/code&gt; force unwraps the optional. If &lt;code&gt;regularFileContents&lt;/code&gt; is nil, setting the &lt;code&gt;data&lt;/code&gt; constant crashes the app.&lt;/p&gt;&#xA;&lt;p&gt;Avoid force unwrapping because it can crash your app.&lt;/p&gt;&#xA;&lt;h4 id=&#34;asexample&#34;&gt;as! Example&lt;/h4&gt;&#xA;&lt;p&gt;The following code demonstrates using &lt;code&gt;as!&lt;/code&gt; to cast to a data type:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;readFont&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; tagData: NSDictionary) -&amp;gt; NSFont? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fontName = tagData[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FontName&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;! String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fontSize = tagData[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FontSize&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;! NSNumber&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; styleFont = NSFont(name: fontName, size: CGFloat(fontSize.floatValue))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; styleFont&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function reads font data from a dictionary in a JSON file. The following line of code reads the font name:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fontName = tagData[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FontName&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;! String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If there isn’t an item in the dictionary with a key named &lt;code&gt;FontName&lt;/code&gt;, the app crashes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;waystofixtheerror&#34;&gt;Ways to fix the error&lt;/h3&gt;&#xA;&lt;p&gt;Use &lt;code&gt;guard&lt;/code&gt; statements to exit early if the optional value is nil.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; data = file.regularFileContents &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// Do anything you need to do if data is nil.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Do something with data, such as load it&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use &lt;code&gt;if let&lt;/code&gt; statements to do something only if the optional value is not nil.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; data = file.regularFileContents {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Do something with data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use &lt;code&gt;as?&lt;/code&gt; instead of &lt;code&gt;as!&lt;/code&gt; to cast to a specific data type.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fontName = tagData[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FontName&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the &lt;code&gt;??&lt;/code&gt; operator to provide a default value if the optional is nil. The following example returns an empty PDF document if you provide a nil URL to create a PDF document:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; PDFDocument(url: fileURL) ?? PDFDocument()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check that the optional value is not nil before unwrapping it. This technique is less elegant than the others, but it will prevent the app from crashing.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; data = file.regularFileContents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; data &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Do something with data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Make sure the outlets in your storyboards are connected. Open the Connections Inspector for the storyboard by choosing View &amp;gt; Inspectors &amp;gt; Connections.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ConnectionsInspector.png&#34; alt=&#34;connections inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The article &lt;a href=&#34;https://www.swiftdevjournal.com/introduction-to-mac-development-connecting-ui-elements/&#34;&gt;Connecting UI Elements&lt;/a&gt; has detailed information on connecting outlets.&lt;/p&gt;&#xA;&lt;h3 id=&#34;additionalreading&#34;&gt;Additional Reading&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/crashing-with-swift-optionals/&#34;&gt;Crashing with Swift Optionals&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/swift-optionals/&#34;&gt;Swift Optionals&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/fixing-and-avoiding-crashes-in-swift-code/&#34;&gt;Fixing and Avoiding Crashes in Swift Code&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Fixing the ForEach requires that T conform to Identifiable error in Swift</title>
      <link>https://swiftdevjournal.com/fixing-the-foreach-requires-that-t-conform-to-identifiable-error-in-swift/</link>
      <pubDate>Wed, 11 Jan 2023 19:11:18 +0000</pubDate>
      <guid>https://swiftdevjournal.com/fixing-the-foreach-requires-that-t-conform-to-identifiable-error-in-swift/</guid>
      <description>&lt;p&gt;The actual error message is too long for an article title. The error message looks like the following:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Error: Referencing initializer ‘init (_:content:)’ on ‘ForEach’ requires that ‘T’ conform to ’Identifiable’&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Where &lt;code&gt;T&lt;/code&gt; is a struct or class.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whyamigettingthiserror&#34;&gt;Why am I getting this error?&lt;/h3&gt;&#xA;&lt;p&gt;You have a ForEach block that does not uniquely identify each item. The compiler needs a way to uniquely identify each item in the ForEach block. If you do not provide a way to uniquely identify the items, you get the error.&lt;/p&gt;&#xA;&lt;p&gt;The most common cause of the error is the only argument you supplied to the ForEach is the collection of items, and the item’s struct or class does not conform to the &lt;code&gt;Identifiable&lt;/code&gt; protocol.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ForEach(items) { item &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;waystofixtheerror&#34;&gt;Ways to fix the error&lt;/h3&gt;&#xA;&lt;p&gt;The easiest way to fix the error is to provide an &lt;code&gt;id&lt;/code&gt; argument to the ForEach and using &lt;code&gt;\.self&lt;/code&gt; as the value.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ForEach(items, id: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { item &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another way to fix the error is to make the struct or class of the items in the ForEach conform to the &lt;code&gt;Identifiable&lt;/code&gt; protocol. Add an &lt;code&gt;id&lt;/code&gt; property to the struct or class that uniquely identifies each instance of the struct or class.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyStruct&lt;/span&gt;: Identifiable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; id = UUID()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The call to &lt;code&gt;UUID&lt;/code&gt; creates a unique identifier for each instance of the struct your app creates.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Fixing the “Async call in a function that doesn’t support concurrency” error in Swift</title>
      <link>https://swiftdevjournal.com/fixing-the-async-call-in-a-function-that-doesnt-support-concurrency-error-in-swift/</link>
      <pubDate>Thu, 05 Jan 2023 19:27:54 +0000</pubDate>
      <guid>https://swiftdevjournal.com/fixing-the-async-call-in-a-function-that-doesnt-support-concurrency-error-in-swift/</guid>
      <description>&lt;p&gt;The error message may also say “Cannot pass function of type ‘() async -&amp;gt; Void’ to parameter expecting synchronous function type”.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whyamigettingthiserror&#34;&gt;Why am I getting this error?&lt;/h3&gt;&#xA;&lt;p&gt;You are using Swift’s async await syntax and calling an async function in a function that does not support async await. If you have the following function that calls an async function:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;myFunction&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  await asyncFunction()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You are going to get the “Async call in a function that doesn’t support concurrency” build error because &lt;code&gt;myFunction&lt;/code&gt; is not an async function.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://developer.apple.com/videos/play/wwdc2021/10132&#34;&gt;Apple added async await support to Swift in 2021&lt;/a&gt; so the support is relatively new. Many of Apple’s frameworks do not support the new async await syntax.&lt;/p&gt;&#xA;&lt;p&gt;Apple’s &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; class, which &lt;a href=&#34;https://www.swiftdevjournal.com/log-in-to-websites-with-aswebauthenticationsession/&#34;&gt;apps use to log into websites&lt;/a&gt;, does not support async await. When you create an instance of &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt;, you supply a completion handler that runs after a successful login. If you make an async function call in the completion handler, you’ll get the “Async call in a function that doesn’t support concurrency” build error.&lt;/p&gt;&#xA;&lt;h3 id=&#34;waystofixtheerror&#34;&gt;Ways to fix the error&lt;/h3&gt;&#xA;&lt;p&gt;The most common way to fix the error is to place the call to the async function in a &lt;code&gt;Task&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Task {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  await asyncFunction()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the error occurs in a function you wrote, you can fix the error by marking that function as async.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;myFunction&lt;/span&gt;() async {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  await asyncFunction()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Don’t forget to add &lt;code&gt;await&lt;/code&gt; when calling the function you marked as async.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Replace Swift print Statements with Xcode Breakpoint Actions</title>
      <link>https://swiftdevjournal.com/replace-swift-print-statements-with-xcode-breakpoint-actions/</link>
      <pubDate>Mon, 12 Dec 2022 19:11:30 +0000</pubDate>
      <guid>https://swiftdevjournal.com/replace-swift-print-statements-with-xcode-breakpoint-actions/</guid>
      <description>&lt;p&gt;When you run into problems with your Swift code, your first instinct may be to add &lt;code&gt;print&lt;/code&gt; statements. There’s nothing wrong with &lt;code&gt;print&lt;/code&gt; statements, but you can also use Xcode breakpoint actions to print to Xcode’s debug console. Using Xcode breakpoint actions instead of &lt;code&gt;print&lt;/code&gt; statements has the following advantages:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;You don’t have to write any code.&lt;/li&gt;&#xA;&lt;li&gt;They fire only when debugging.&lt;/li&gt;&#xA;&lt;li&gt;You can turn them on and off easily without having to rebuild your project.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Take the following steps to create a breakpoint action equivalent of a &lt;code&gt;print&lt;/code&gt; statement.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Add a breakpoint.&lt;/li&gt;&#xA;&lt;li&gt;Add a breakpoint action.&lt;/li&gt;&#xA;&lt;li&gt;Choose Log Message from the breakpoint action menu.&lt;/li&gt;&#xA;&lt;li&gt;Enter what you want to print in the text field.&lt;/li&gt;&#xA;&lt;li&gt;Select the Automatically continue after running checkbox.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;addabreakpoint&#34;&gt;Add a Breakpoint&lt;/h3&gt;&#xA;&lt;p&gt;Click on the left side of Xcode’s editor next to the line of code where you want to set the breakpoint.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/EnabledBreakpoint.png&#34; alt=&#34;enabled breakpoint&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The breakpoint appears as a blue arrow in the editor.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addabreakpointaction&#34;&gt;Add a Breakpoint Action&lt;/h3&gt;&#xA;&lt;p&gt;Right-click on a breakpoint in Xcode’s editor or in Xcode’s breakpoint navigator (Press Cmd–8) and choose Edit Breakpoint. A popover opens to edit the breakpoint.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeBreakpointEditor.png&#34; alt=&#34;breakpoint editor&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the Add Action button to add a breakpoint action.&lt;/p&gt;&#xA;&lt;h3 id=&#34;printingtext&#34;&gt;Printing Text&lt;/h3&gt;&#xA;&lt;p&gt;Clicking the Add Action button expands the breakpoint editor.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeBreakpointActionEditor.png&#34; alt=&#34;breakpoint action editor&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Choose Log Message from the Action menu. The Log Message action is the equivalent of a Swift &lt;code&gt;print&lt;/code&gt; statement.&lt;/p&gt;&#xA;&lt;p&gt;If you want to show that you entered a function in your code, enter the text in the text field.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Reached viewDidLoad.&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you want to print the value of a variable, wrap it with the @ character. The following message:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Player X: @player.position.x@&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Prints the following in Xcode’s debug console if the x position is 12:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Player X: 12&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;automaticallycontinue&#34;&gt;Automatically Continue&lt;/h3&gt;&#xA;&lt;p&gt;At the bottom of the breakpoint editor is a checkbox to automatically continue after running the breakpoint action. Select the checkbox.&lt;/p&gt;&#xA;&lt;p&gt;Now if you run your project, the messages will appear in Xcode’s Debug console. You created the equivalent of a &lt;code&gt;print&lt;/code&gt; statement without writing any code.&lt;/p&gt;&#xA;&lt;h3 id=&#34;turningoffprinting&#34;&gt;Turning off Printing&lt;/h3&gt;&#xA;&lt;p&gt;To turn off printing, disable the breakpoint. Click on the breakpoint in Xcode’s source editor to disable the breakpoint. Click a disabled breakpoint to enable it.&lt;/p&gt;&#xA;&lt;h3 id=&#34;relatedreading&#34;&gt;Related Reading&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/an-introduction-to-xcodes-debugger/&#34;&gt;An Introduction to Xcode’s Debugger&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/xcode-breakpoint-actions/&#34;&gt;Xcode Breakpoint Actions&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Showing a Swift Enum’s Values in a SwiftUI Picker</title>
      <link>https://swiftdevjournal.com/showing-a-swift-enums-values-in-a-swiftui-picker/</link>
      <pubDate>Tue, 06 Dec 2022 18:53:43 +0000</pubDate>
      <guid>https://swiftdevjournal.com/showing-a-swift-enums-values-in-a-swiftui-picker/</guid>
      <description>&lt;p&gt;Swift enums let you create your own data types with a limited number of possible values. You may want to use a picker in a SwiftUI app to choose one of the enum’s values. Filling a picker with an enum’s values requires you to do two things.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Make the enum conform to the &lt;code&gt;CaseIterable&lt;/code&gt; protocol.&lt;/li&gt;&#xA;&lt;li&gt;Wrap the picker in a &lt;code&gt;ForEach&lt;/code&gt; block, supplying an array of the enum’s values.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;conformingtocaseiterable&#34;&gt;Conforming to CaseIterable&lt;/h3&gt;&#xA;&lt;p&gt;Your Swift enum must conform to the &lt;code&gt;CaseIterable&lt;/code&gt; protocol to get an array of the enum’s values. In most cases, conforming to &lt;code&gt;CaseIterable&lt;/code&gt; is easy. Add &lt;code&gt;CaseIterable&lt;/code&gt; after a colon when creating the enum. The following code shows a simple enum that conforms to &lt;code&gt;CaseIterable&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IssuePriority&lt;/span&gt;: Int, CaseIterable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; low = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; medium = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; high = &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Convert to string to display in menus and pickers.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stringValue&lt;/span&gt;() -&amp;gt; String {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .low:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Low&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .medium:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Medium&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; .high:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;High&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By conforming to &lt;code&gt;CaseIterable&lt;/code&gt;, the enum gets an &lt;code&gt;allCases&lt;/code&gt; property that contains an array of the enum’s values. Use the property in a picker or any other SwiftUI view that shows an array of items.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wrapthepickerinaforeachblock&#34;&gt;Wrap the Picker in a ForEach Block&lt;/h3&gt;&#xA;&lt;p&gt;To provide picker items for each enum value, wrap the picker in a &lt;code&gt;ForEach&lt;/code&gt; block. Supply the enum’s &lt;code&gt;allCases&lt;/code&gt; property in the &lt;code&gt;ForEach&lt;/code&gt; block. Create a &lt;code&gt;Text&lt;/code&gt; view or whatever view you want for the picker item. The following code demonstrates how to create a picker with items for each value in the &lt;code&gt;IssuePriority&lt;/code&gt; enum from the previous section:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; issuePriority: IssuePriority = .low&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Picker(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Issue Priority:&amp;#34;&lt;/span&gt;, selection: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;issuePriority) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ForEach(IssuePriority.allCases, id: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { priority &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; menuText = priority.stringValue()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;menuText&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .tag(priority)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Genrerating Swift Code for REST APIs with CreateAPI</title>
      <link>https://swiftdevjournal.com/genrerating-swift-code-for-rest-apis-with-createapi/</link>
      <pubDate>Mon, 21 Nov 2022 19:26:12 +0000</pubDate>
      <guid>https://swiftdevjournal.com/genrerating-swift-code-for-rest-apis-with-createapi/</guid>
      <description>&lt;p&gt;If you are starting to develop a Swift app that works with a REST API, you may be overwhelmed thinking about all the code you have to write. What if you forget a data structure? What if you forget to add a property to a data structure? Wouldn’t it be nice to have someone create the Swift code for you?&lt;/p&gt;&#xA;&lt;p&gt;The command-line app &lt;a href=&#34;https://github.com/CreateAPI/CreateAPI&#34;&gt;CreateAPI&lt;/a&gt; makes this possible. Supply a JSON or YAML file that contains the REST API, and CreateAPI creates a Swift package with Swift code for the REST API. By using CreateAPI you can make faster progress on a Swift app that uses REST APIs.&lt;/p&gt;&#xA;&lt;h3 id=&#34;installingcreateapi&#34;&gt;Installing CreateAPI&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://github.com/CreateAPI/CreateAPI&#34;&gt;CreateAPI GitHub page&lt;/a&gt; has installation instructions. You can install it using Homebrew or Mint or by cloning the GitHub repository and installing it from source. Installing from source worked for me.&lt;/p&gt;&#xA;&lt;h3 id=&#34;generatingaswiftpackagewithcreateapi&#34;&gt;Generating a Swift Package with CreateAPI&lt;/h3&gt;&#xA;&lt;p&gt;Generating a Swift package with CreateAPI has the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Download a JSON or YAML file that contains the REST API.&lt;/li&gt;&#xA;&lt;li&gt;Open the Terminal app.&lt;/li&gt;&#xA;&lt;li&gt;Navigate to the folder that contains the file.&lt;/li&gt;&#xA;&lt;li&gt;Run CreateAPI.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;The most common way to run CreateAPI is to run the &lt;code&gt;create-api generate&lt;/code&gt; command with the &lt;code&gt;--output&lt;/code&gt; and &lt;code&gt;--config-option&lt;/code&gt; options. The following example demonstrates running CreateAPI:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;create-api generate &amp;#34;APIFile.json&amp;#34; &#xA;  --output &amp;#34;./PackageName&amp;#34; &#xA;  --config-option &amp;#34;module=PackageName&amp;#34;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The name of the JSON file must be in quotes. Replace &lt;code&gt;APIFile.json&lt;/code&gt; with the name of the file containing the REST API. Replace &lt;code&gt;PackageName&lt;/code&gt; with the name you want for your Swift package.&lt;/p&gt;&#xA;&lt;p&gt;The CreateAPI GitHub page &lt;a href=&#34;https://github.com/CreateAPI/CreateAPI/blob/main/Docs/Tutorial.md&#34;&gt;has a tutorial&lt;/a&gt; that contains more detailed instructions.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;CreateAPI is in its early stages of development. It may not work with every REST API. I was unable to generate a Swift package for GitHub’s REST API.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addthepackagetoyourxcodeproject&#34;&gt;Add the Package to Your Xcode Project&lt;/h3&gt;&#xA;&lt;p&gt;After creating the Swift package you can add it to your project like any other Swift package. If you have never added a Swift package to a project in Xcode, take the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Select the project file from the left side of the project window to open the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Select the project from the left side of the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Click the Package Dependencies button at the top of the project editor to show a list of Swift packages in the project.&lt;/li&gt;&#xA;&lt;li&gt;Click the Add button at the bottom of the package list.&lt;/li&gt;&#xA;&lt;li&gt;Click the Add Local button in the sheet to add your package.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Import the package module in your source code files, and you can start using the package in your app.&lt;/p&gt;&#xA;&lt;p&gt;If you want to see an example of a Swift package that CreateAPI creates, I have &lt;a href=&#34;https://github.com/SwiftDevJournal/JiraKit&#34;&gt;a package for Jira’s REST API on GitHub&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Navigation Basics for SwiftUI on macOS</title>
      <link>https://swiftdevjournal.com/navigation-basics-for-swiftui-on-macos/</link>
      <pubDate>Fri, 11 Nov 2022 03:00:17 +0000</pubDate>
      <guid>https://swiftdevjournal.com/navigation-basics-for-swiftui-on-macos/</guid>
      <description>&lt;p&gt;If you’re looking for information on using the new SwiftUI navigation APIs in a Mac app, check out the following article:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.kiloloco.com/articles/019-swiftui-macos-navigation-basics/&#34;&gt;https://www.kiloloco.com/articles/019-swiftui-macos-navigation-basics/&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Working with Lists in Multiplatform SwiftUI Apps</title>
      <link>https://swiftdevjournal.com/working-with-lists-in-multiplatform-swiftui-apps/</link>
      <pubDate>Mon, 07 Nov 2022 18:34:36 +0000</pubDate>
      <guid>https://swiftdevjournal.com/working-with-lists-in-multiplatform-swiftui-apps/</guid>
      <description>&lt;p&gt;One of SwiftUI’s best features is you can use it to make apps that run on both iOS and Mac. Almost every SwiftUI article you find online is about iOS development, but most of the material also applies to Mac as well.&lt;/p&gt;&#xA;&lt;p&gt;Lists are one area of SwiftUI where there are large differences between iOS and Mac. If you read an article about lists and try to use the code in a Mac app, you’ll run into problems. This article provides guidance on writing list code that works in both iOS and Mac apps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;differencesinlistbehavior&#34;&gt;Differences in List Behavior&lt;/h3&gt;&#xA;&lt;p&gt;The main reason you can’t use the same list code on iOS and Mac is because the way people interact with lists is different in iOS and Mac.&lt;/p&gt;&#xA;&lt;p&gt;iOS apps have an Edit button that people use to delete and move items. When someone wants to delete a list item, they tap the Edit button. Each item has a Delete button next to it. Tapping the button deletes the item. Because each list item has a Delete button, you don’t have to keep track of the selected items.&lt;/p&gt;&#xA;&lt;p&gt;Mac apps don’t have an Edit button for deleting and moving list items. In a Mac app, people delete list items by selecting them and either pressing the Delete key or clicking a Delete button. People move items by selecting them and dragging them to the desired destination. When developing a Mac app that uses lists, you must keep track of the selected item.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tip:createseparatelistviewsforiosandmacapptargets&#34;&gt;Tip: Create Separate List Views for iOS and Mac App Targets&lt;/h3&gt;&#xA;&lt;p&gt;Because list behavior is so different between iOS and Mac apps, you should create separate SwiftUI list views for the iOS and Mac versions of your app. If you try to support iOS and Mac in the same view, your code is going to be littered with &lt;code&gt;#if os()&lt;/code&gt; checks, making the code tough to read.&lt;/p&gt;&#xA;&lt;p&gt;You can share a list view if the list only displays data. If your app doesn’t allow people to delete and move items, it doesn’t require an Edit button on iOS. In that case you can share the view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;deletinglistitems&#34;&gt;Deleting List Items&lt;/h3&gt;&#xA;&lt;h4 id=&#34;ios&#34;&gt;iOS&lt;/h4&gt;&#xA;&lt;p&gt;Deleting a list item on iOS requires the following steps:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Place the list items in a &lt;code&gt;ForEach&lt;/code&gt; block.&lt;/li&gt;&#xA;&lt;li&gt;Add an &lt;code&gt;.onDelete&lt;/code&gt; modifier to the &lt;code&gt;ForEach&lt;/code&gt; block.&lt;/li&gt;&#xA;&lt;li&gt;Write a function to delete the item from its array.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;You can’t apply the &lt;code&gt;.onDelete&lt;/code&gt; modifier directly to a list on iOS. That’s why you must place the list items in a &lt;code&gt;ForEach&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;p&gt;Call the function to delete the item in &lt;code&gt;.onDelete&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.onDelete(perform: deleteItem)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function to delete the item takes an &lt;code&gt;IndexSet&lt;/code&gt; as an argument. Call the array’s &lt;code&gt;remove&lt;/code&gt; function to remove the item from the array.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;deleteItem&lt;/span&gt;(at offsets: IndexSet) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  array.remove(atOffsets: offsets)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;mac&#34;&gt;Mac&lt;/h4&gt;&#xA;&lt;p&gt;Deleting a list item on Mac requires the following steps:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Keep track of the selected item.&lt;/li&gt;&#xA;&lt;li&gt;Add an &lt;code&gt;.onDeleteCommand&lt;/code&gt; modifier to the list.&lt;/li&gt;&#xA;&lt;li&gt;Write a function to delete the item from its array.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The usual way to keep track of the selected list item is to add a &lt;code&gt;@State&lt;/code&gt; property to the view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; selection: Model? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Call the function to delete the item in &lt;code&gt;.onDeleteCommand&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.onDeleteCommand {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  deleteItem()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Removing an item from an array in a Mac app is trickier. Call the array’s &lt;code&gt;firstIndex&lt;/code&gt; function to find the selected item in the array. If the item is in the array, call the &lt;code&gt;remove&lt;/code&gt; function to delete the item.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;deleteItem&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; selection = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.selection,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; selectionIndex = array.firstIndex(of: selection) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    array.remove(at: selectionIndex)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;movinglistitems&#34;&gt;Moving List Items&lt;/h3&gt;&#xA;&lt;h4 id=&#34;ios&#34;&gt;iOS&lt;/h4&gt;&#xA;&lt;p&gt;Moving list items on iOS requires the following steps:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Place the list items in a &lt;code&gt;ForEach&lt;/code&gt; block.&lt;/li&gt;&#xA;&lt;li&gt;Add an &lt;code&gt;.onMove&lt;/code&gt; modifier to the &lt;code&gt;ForEach&lt;/code&gt; block.&lt;/li&gt;&#xA;&lt;li&gt;Add a function to move the item in its array.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;You can’t apply the &lt;code&gt;.onMove&lt;/code&gt; modifier directly to a list on iOS. That’s why you must place the list items in a &lt;code&gt;ForEach&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;move&lt;/code&gt; function in &lt;code&gt;.onMove&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.onMove(perform: move)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;move&lt;/code&gt; function takes two arguments: a location for the source and a location for the destination. Call the array’s &lt;code&gt;move&lt;/code&gt; function to move the items in the array.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;move&lt;/span&gt;(from source: IndexSet, to destination: Int) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  array.move(fromOffsets: source, toOffset: destination) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;mac&#34;&gt;Mac&lt;/h4&gt;&#xA;&lt;p&gt;Moving list items on Mac requires the following steps:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Add an &lt;code&gt;.onMove&lt;/code&gt; modifier to the list.&lt;/li&gt;&#xA;&lt;li&gt;Add a function to move the item in its array.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;You have to do a little more work on Mac with the &lt;code&gt;.onMove&lt;/code&gt; modifier, providing the arguments in the closure to call the &lt;code&gt;move&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.onMove { indices, destination &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  move(from: indices, to: destination)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;move&lt;/code&gt; function is the same as iOS.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;move&lt;/span&gt;(from source: IndexSet, to destination: Int) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  array.move(fromOffsets: source, toOffset: destination)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;wantmorearticleslikethis&#34;&gt;Want More Articles Like This?&lt;/h3&gt;&#xA;&lt;p&gt;This article is an example of the exclusive articles for Swift Dev Journal newsletter subscribers. Subscribers also get a guide on going from tutorials to making your first app, discounts on books, and any benefits I decide to add later.&lt;/p&gt;&#xA;&lt;p&gt;Use the form at the end of this article to subscribe to the newsletter.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Saving Images in Core Data</title>
      <link>https://swiftdevjournal.com/saving-images-in-core-data/</link>
      <pubDate>Mon, 31 Oct 2022 18:06:03 +0000</pubDate>
      <guid>https://swiftdevjournal.com/saving-images-in-core-data/</guid>
      <description>&lt;p&gt;A common question I see on Swift developer forums is how to save images in Core Data. You have to do the following to save an image in Core Data:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Add an attribute for the image with data type Binary Data.&lt;/li&gt;&#xA;&lt;li&gt;Use external storage to save the image in a separate file.&lt;/li&gt;&#xA;&lt;li&gt;Convert the image to a &lt;code&gt;Data&lt;/code&gt; object to save it in Core Data.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;addattributeoftypebinarydata&#34;&gt;Add Attribute of Type Binary Data&lt;/h3&gt;&#xA;&lt;p&gt;Core Data does not have a data type specifically for images. Binary data is the closest data type that Core Data supports.&lt;/p&gt;&#xA;&lt;h3 id=&#34;useexternalstorage&#34;&gt;Use External Storage&lt;/h3&gt;&#xA;&lt;p&gt;Images take a lot of space so it’s more efficient to save them in separate files instead of saving them in the persistent store where Core Data saves your app’s data.&lt;/p&gt;&#xA;&lt;p&gt;To tell Core Data to save the image in its own file, select the attribute and open the data model inspector. Choose View &amp;gt; Inpsectors &amp;gt; Data Model to open the data model inspector.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CoreDataUseExternalStorage.png&#34; alt=&#34;use external storage&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the Allows External Storage checkbox to save the image in a separate file.&lt;/p&gt;&#xA;&lt;h3 id=&#34;converttheimagetoadataobject&#34;&gt;Convert the Image to a Data Object&lt;/h3&gt;&#xA;&lt;p&gt;You must convert the image to a &lt;code&gt;Data&lt;/code&gt; object to set the image attribute’s value in your code. &lt;code&gt;Data&lt;/code&gt; is the underlying data type for a Core Data attribute of type Binary Data.&lt;/p&gt;&#xA;&lt;p&gt;Swift apps generally use either &lt;code&gt;UIImage&lt;/code&gt; or &lt;code&gt;NSImage&lt;/code&gt; to work with images. UIImage has &lt;code&gt;pngData&lt;/code&gt; and &lt;code&gt;jpegData&lt;/code&gt; functions to convert an image to &lt;code&gt;Data&lt;/code&gt;. NSImage has a &lt;code&gt;tiffRepresentation&lt;/code&gt; function to convert to &lt;code&gt;Data&lt;/code&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Xcode Multiplatform App Targets</title>
      <link>https://swiftdevjournal.com/xcode-multiplatform-app-targets/</link>
      <pubDate>Mon, 24 Oct 2022 17:57:43 +0000</pubDate>
      <guid>https://swiftdevjournal.com/xcode-multiplatform-app-targets/</guid>
      <description>&lt;p&gt;Starting in Xcode 14, when you create a multiplatform app project, Xcode creates a single app target with destinations for each platform you want to support: iPhone, iPad, Apple TV and Mac. This article provides an introduction to multiplatform app targets.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whentousethemultiplatformapptarget&#34;&gt;When to Use the Multiplatform App Target&lt;/h3&gt;&#xA;&lt;p&gt;Use the Multiplatform App Target if you want people to buy one version of your app on the App Store and run the app on all the platforms you support: iPhone, iPad, AppleTV, and/or Mac. Use separate targets if you plan to charge for each platform separately.&lt;/p&gt;&#xA;&lt;p&gt;If you plan to sell a Mac version of your app outside the App Store, create a separate app target. Use the multiplatform app target to sell on the App Store and the Mac app target to sell outside the App Store.&lt;/p&gt;&#xA;&lt;h3 id=&#34;viewingaddingandremovingplatformdestinations&#34;&gt;Viewing, Adding, and Removing Platform Destinations&lt;/h3&gt;&#xA;&lt;p&gt;Select the target from the target list on the left side of the project editor and click the General button at the top of the project editor to see a list of the app’s platform destinations:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AppTargetSupportedDestinations.png&#34; alt=&#34;supported destinations&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The supported destinations list has buttons to add and remove destinations. If you created a project in an older version of Xcode, you must add destinations to have a single app target that supports iPhone, iPad, AppleTV, and Mac. Older versions of Xcode have separate targets for each platform.&lt;/p&gt;&#xA;&lt;h4 id=&#34;macdestinationchoices&#34;&gt;Mac Destination Choices&lt;/h4&gt;&#xA;&lt;p&gt;When adding the Mac destination to an app target, you have the following choices:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Mac&lt;/li&gt;&#xA;&lt;li&gt;Mac Catalyst&lt;/li&gt;&#xA;&lt;li&gt;Designed for iPad&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Choosing Mac uses SwiftUI and/or AppKit for the Mac app. Mac is the best choice for a new app, especially one that uses SwiftUI.&lt;/p&gt;&#xA;&lt;p&gt;Choosing Mac Catalyst uses UIKit for the Mac app. Mac Catalyst is the best choice if you want to make a Mac version of an existing iOS app.&lt;/p&gt;&#xA;&lt;p&gt;Choosing Designed for iPad runs the iPad version of the app on Macs with Apple Silicon chips. Choose Designed for iPad if you want a Mac version of your iOS app and don’t want to do any work converting the app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;choosingtheplatformtobuildandrun&#34;&gt;Choosing the Platform to Build and Run&lt;/h3&gt;&#xA;&lt;p&gt;Xcode can build and run for only platform at a time. How do you specify the platform to build and run?&lt;/p&gt;&#xA;&lt;p&gt;There’s a jump bar in the project window toolbar.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ChoosePlatformToRun.png&#34; alt=&#34;choose platform to run&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the right part of the jump bar to choose the platform: Mac, a connected iOS device, or an iOS simulator.&lt;/p&gt;&#xA;&lt;h3 id=&#34;compilingfilesforspecificplatforms&#34;&gt;Compiling Files for Specific Platforms&lt;/h3&gt;&#xA;&lt;p&gt;Previous versions of Xcode have separate targets for each platform. If you have separate targets with code that should be compiled for a specific platform, make the file a member of that target. But you can’t do that with the multiplatform app target because there’s only one target. What do you do if you have platform-specific source code files?&lt;/p&gt;&#xA;&lt;p&gt;Tell Xcode what platforms a source code file should compile for. Click the Build Phases button at the top of the project editor and examine the Compile Sources build phase.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/FilterDestinations.png&#34; alt=&#34;filter destinations&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Xcode initially sets each source code file to build for each destination. Click on the Filter column for a source code file to open a popover.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/PlatformFilterPopover.png&#34; alt=&#34;platform filter popover&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Deselect the Allow any platform checkbox and deselect the destinations you don’t want to use. Now that file compiles only for the platforms you specified.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Using the Sparkle Framework in a Sandboxed App</title>
      <link>https://swiftdevjournal.com/using-the-sparkle-framework-in-a-sandboxed-app/</link>
      <pubDate>Mon, 26 Sep 2022 18:19:45 +0000</pubDate>
      <guid>https://swiftdevjournal.com/using-the-sparkle-framework-in-a-sandboxed-app/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://sparkle-project.org&#34;&gt;Sparkle&lt;/a&gt; is a framework that simplifies updating Mac apps that are not on the Mac App Store. There is a &lt;a href=&#34;https://sparkle-project.org/documentation/sandboxing/&#34;&gt;guide for using Sparkle in a sandboxed app&lt;/a&gt;, but I found parts of it unclear so I’m writing about it in this article.&lt;/p&gt;&#xA;&lt;p&gt;It is very important to set things up correctly with the initial version of your app. If you forget to add something to either the entitlements file or the &lt;code&gt;Info.plist&lt;/code&gt; file, people will see the following alert when they try to install an update for your app:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SparkleUpdateErrorAlert.png&#34; alt=&#34;Sparkle update error alert&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;overview&#34;&gt;Overview&lt;/h3&gt;&#xA;&lt;p&gt;You have to perform one or more of the following steps to properly add Sparkle support to a sandboxed app:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Add the Installer Service (required)&lt;/li&gt;&#xA;&lt;li&gt;Add the Installer Connection and Status Services (probably required)&lt;/li&gt;&#xA;&lt;li&gt;Add the Downloader Service (maybe)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Most sandboxed apps only need to perform the first two steps. You may have to do more if you have more complex update requirements. See the &lt;a href=&#34;https://sparkle-project.org/documentation/sandboxing/&#34;&gt;sandboxing guide&lt;/a&gt; for those cases.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addtheinstallerservice&#34;&gt;Add the Installer Service&lt;/h3&gt;&#xA;&lt;p&gt;To add the Installer Service to your app, you must add the following entry to the &lt;code&gt;Info.plist&lt;/code&gt; file:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Key: SUEnableInstallerLauncherService&#xA;Type: Boolean&#xA;Value: YES&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;addtheinstallerconnectionandstatusservices&#34;&gt;Add the Installer Connection and Status Services&lt;/h3&gt;&#xA;&lt;p&gt;To add the Installer Connection and Status Services to your app, you must add the following entry to your app’s entitlements file:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Key: com.apple.security.temporary-exception.mach-lookup.global-name&#xA;Type: Array&#xA;    &#xA;Key: Item 0&#xA;Type: String&#xA;Value: $(PRODUCT_BUNDLE_IDENTIFIER)-spks&#xA;    &#xA;Key: Item 1&#xA;Type: String&#xA;Value: $(PRODUCT_BUNDLE_IDENTIFIER)-spki&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The entry is an array with two string items.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addthedownloaderservice&#34;&gt;Add the Downloader Service&lt;/h3&gt;&#xA;&lt;p&gt;If you have the Outgoing Connections checkbox selected in the App Sandbox settings, you can skip this section. You’re done.&lt;/p&gt;&#xA;&lt;p&gt;If your app does not allow outgoing connections (the Outgoing Connections checkbox is not selected), you must add the Downloader Service to update your app with Sparkle. Add the following entry to the &lt;code&gt;Info.plist&lt;/code&gt; file:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Key: SUEnableDownloaderService&#xA;Type: Boolean&#xA;Value: YES&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;furtherreading&#34;&gt;Further Reading&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://sparkle-project.org/documentation/&#34;&gt;Sparkle’s documentation&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://sparkle-project.org/documentation/sandboxing/&#34;&gt;Sparkle’s sandboxing guide&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://swiftdevjournal.com/code-signing-and-the-sparkle-framework&#34;&gt;Code Signing and the Sparkle Framework&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://swiftdevjournal.com/accessing-the-sparkle-binary-from-its-swift-package&#34;&gt;Accessing the Sparkle Binary from its Swift Package&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Accessing the Sparkle Binary from its Swift Package</title>
      <link>https://swiftdevjournal.com/accessing-the-sparkle-binary-from-its-swift-package/</link>
      <pubDate>Wed, 21 Sep 2022 17:35:26 +0000</pubDate>
      <guid>https://swiftdevjournal.com/accessing-the-sparkle-binary-from-its-swift-package/</guid>
      <description>&lt;p&gt;A common task when using the &lt;a href=&#34;https://sparkle-project.org&#34;&gt;Sparkle framework&lt;/a&gt; is to update the appcast when you release an update to your app. Running the command to update the appcast requires access to the Sparkle binary. Finding the Sparkle binary can be difficult if you added Sparkle using the Swift Package Manager. But by using Xcode and the Finder, you can create a Terminal window in the right location to run Sparkle commands.&lt;/p&gt;&#xA;&lt;h3 id=&#34;overview&#34;&gt;Overview&lt;/h3&gt;&#xA;&lt;p&gt;Running a Sparkle command when using the Swift Package Manager requires the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Locate the Sparkle binary folder in the Finder.&lt;/li&gt;&#xA;&lt;li&gt;Go to the Sparkle binary folder in the Terminal.&lt;/li&gt;&#xA;&lt;li&gt;Run the Sparkle command.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;locatethesparklebinaryfolderinthefinder&#34;&gt;Locate the Sparkle Binary Folder in the Finder&lt;/h3&gt;&#xA;&lt;p&gt;The easiest way to find the Sparkle binary folder is to use Xcode. The project navigator has an entry for Sparkle in the Package Dependencies section. Click the disclosure triangle next to the Sparkle entry.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AccessingSparkleToolsFromSwiftPackageManager.png&#34; alt=&#34;accessing Sparkle tools&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The Sparkle binary is in the Referenced Binaries section. Select the Sparkle binary, right-click, and choose Show in Finder to open the Sparkle binary folder in the Finder.&lt;/p&gt;&#xA;&lt;h4 id=&#34;xcode14update&#34;&gt;Xcode 14 Update&lt;/h4&gt;&#xA;&lt;p&gt;Xcode 14 does not have a Referenced Binaries selection. Select the Sparkle 2.x item from the project navigator, right-click, and choose Show in Finder.&lt;/p&gt;&#xA;&lt;p&gt;When you choose Show in Finder, the Finder takes you to a &lt;code&gt;Sparkle&lt;/code&gt; folder inside a &lt;code&gt;checkouts&lt;/code&gt; folder. That &lt;code&gt;Sparkle&lt;/code&gt; folder contains source code, not the scripts you need to run.&lt;/p&gt;&#xA;&lt;p&gt;Move one directory above the &lt;code&gt;checkouts&lt;/code&gt; folder, which should be named &lt;code&gt;Source Packages&lt;/code&gt;. Go to the &lt;code&gt;artifacts&lt;/code&gt; folder. That’s where the &lt;code&gt;Sparkle&lt;/code&gt; folder you need is.&lt;/p&gt;&#xA;&lt;h3 id=&#34;gotothesparklebinaryfolderintheterminal&#34;&gt;Go to the Sparkle Binary Folder in the Terminal&lt;/h3&gt;&#xA;&lt;p&gt;In the Finder you have to navigate one folder above the Sparkle folder to open the Sparkle folder in the Terminal. In the Finder toolbar is the name of the current folder, which should be Sparkle. Select the folder name, right-click and choose artifacts to move to the artifacts folder.&lt;/p&gt;&#xA;&lt;p&gt;In the artifacts folder, select the Sparkle folder, right-click, and choose Services &amp;gt; New Terminal at Folder. A new terminal window will open at the correct location to run Sparkle commands.&lt;/p&gt;&#xA;&lt;h3 id=&#34;runthesparklecommandfromtheterminal&#34;&gt;Run the Sparkle Command from the Terminal&lt;/h3&gt;&#xA;&lt;p&gt;Now that you are in the right folder in the Terminal, you can run Sparkle commands. Since updating the appcast is the command you’ll run the most, I’ll use that as an example. To update the appcast, run the following command:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;./bin/generate_appcast &amp;#34;/path/to/your app/Sparkle files&amp;#34; &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where the path is the path to the folder where the &lt;code&gt;appcast.xml&lt;/code&gt; file and the app file you are distributing (the .zip or .dmg file) reside on your Mac. I recommend placing those files in a place that is easy to reference so you don’t have to type an insanely long path to update the appcast.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Passing Data to SwiftUI Views</title>
      <link>https://swiftdevjournal.com/passing-data-to-swiftui-views/</link>
      <pubDate>Mon, 12 Sep 2022 18:51:04 +0000</pubDate>
      <guid>https://swiftdevjournal.com/passing-data-to-swiftui-views/</guid>
      <description>&lt;p&gt;A common question I see from people learning SwiftUI is how to pass data from one view to another. There are three ways to pass data in SwiftUI apps.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Use &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@Binding&lt;/code&gt; property wrappers&lt;/li&gt;&#xA;&lt;li&gt;Use &lt;code&gt;@StateObject&lt;/code&gt; and &lt;code&gt;@ObservedObject&lt;/code&gt; property wrappers&lt;/li&gt;&#xA;&lt;li&gt;Use &lt;code&gt;@EnvironmentObject&lt;/code&gt; property wrapper&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;You’re going to use the first two ways more than you’ll use &lt;code&gt;@EnvironmentObject&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;usestateandbindingforstructs&#34;&gt;Use &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@Binding&lt;/code&gt; for Structs&lt;/h3&gt;&#xA;&lt;p&gt;If you use structs for your data, you must use &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@Binding&lt;/code&gt; to pass data. Use the &lt;code&gt;@State&lt;/code&gt; property wrapper in the master view and the &lt;code&gt;@Binding&lt;/code&gt; property wrapper in any view where you want to pass the data.&lt;/p&gt;&#xA;&lt;p&gt;Suppose you have a wiki app. The wiki consists of a list of pages. There are two views: the master view has a list of pages, and the detail view shows the contents of the selected page.&lt;/p&gt;&#xA;&lt;p&gt;The master view needs to store the selected page.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; selectedPage: Page = Page()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The detail view needs access to the selected page.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; page: Page&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following line of code demonstrates how to pass the selected page from the master view to the detail view:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NavigationLink(destination: PageView(page: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;selectedPage))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When using bindings, you must put the &lt;code&gt;$&lt;/code&gt; character before the name of the &lt;code&gt;@State&lt;/code&gt; variable.&lt;/p&gt;&#xA;&lt;p&gt;The master and detail view point to the same page. Any changes you make in the detail view will appear in both views.&lt;/p&gt;&#xA;&lt;p&gt;I have a &lt;a href=&#34;https://github.com/SwiftDevJournal/WikiDemo&#34;&gt;demo project on GitHub&lt;/a&gt; that provides a full example on using &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@Binding&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;usestateobjectforclasses&#34;&gt;Use &lt;code&gt;@StateObject&lt;/code&gt; and &lt;code&gt;@ObservedObject&lt;/code&gt; for Classes&lt;/h3&gt;&#xA;&lt;p&gt;Use the &lt;code&gt;@StateObject&lt;/code&gt; property to pass a class instance to other views. Using &lt;code&gt;@StateObject&lt;/code&gt; has the following requirements:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The class must conform to the &lt;code&gt;ObservableObject&lt;/code&gt; protocol.&lt;/li&gt;&#xA;&lt;li&gt;Any properties you want automatically updated must use the @Published property wrapper.&lt;/li&gt;&#xA;&lt;li&gt;The SwiftUI views must use the &lt;code&gt;@StateObject&lt;/code&gt; and &lt;code&gt;@ObservedObject&lt;/code&gt; property wrappers.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Suppose you have a &lt;code&gt;Project&lt;/code&gt; class that has a list of issues.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Project&lt;/span&gt;: ObservableObject {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Published &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; issues: [Issue]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By making the class conform to &lt;code&gt;ObservableObject&lt;/code&gt; and using @Published for the &lt;code&gt;issues&lt;/code&gt; array, you can use &lt;code&gt;@StateObject&lt;/code&gt; in the view that owns the project.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@StateObject &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; project: Project&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pass the &lt;code&gt;project&lt;/code&gt; variable to any view that needs to access the project. The other views should use &lt;code&gt;@ObservedObject&lt;/code&gt; so that all the views are referring to the same project.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@ObservedObject &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; project: Project&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Remember that &lt;code&gt;@StateObject&lt;/code&gt; is the class equivalent of &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@ObservedObject&lt;/code&gt; is the class equivalent of &lt;code&gt;@Binding&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I have &lt;a href=&#34;https://github.com/SwiftDevJournal/PersonalIssueTracker&#34;&gt;an issue tracking project on GitHub&lt;/a&gt; that demonstrates passing data to views using &lt;code&gt;@StateObject&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;useenvironmentobjectfordatayouwantanyviewtoaccess&#34;&gt;Use &lt;code&gt;@EnvironmentObject&lt;/code&gt; for Data You Want Any View to Access&lt;/h3&gt;&#xA;&lt;p&gt;Create an environment object when you have a piece of data you want any SwiftUI view to access.&lt;/p&gt;&#xA;&lt;p&gt;A common situation where you would use environment objects is an app that uses Core Data. When working with Core Data, your app needs to access the managed object context to add, update, and delete entities. Apple provides an environment object for the managed object context so you don’t have to create one. Use the &lt;code&gt;@Environment&lt;/code&gt; property wrapper to access the managed object context.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Environment(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.managedObjectContext) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; context&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you need to create your own environment object, you must create a class that conforms to &lt;code&gt;ObservableObject&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;In the SwiftUI view, use the &lt;code&gt;@EnvironmentObject&lt;/code&gt; property wrapper to access your environment object.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@EnvironmentObject &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; project: Project&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the &lt;code&gt;.environmentObject&lt;/code&gt; modifier to pass the environment object to another view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DetailView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .environmentObject(project)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Getting Started with the Get Networking Framework</title>
      <link>https://swiftdevjournal.com/getting-started-with-the-get-networking-framework/</link>
      <pubDate>Mon, 15 Aug 2022 18:39:47 +0000</pubDate>
      <guid>https://swiftdevjournal.com/getting-started-with-the-get-networking-framework/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://github.com/kean/Get&#34;&gt;Get framework&lt;/a&gt; is a lightweight Swift framework for working with web APIs. Get is a nice framework, but the README file doesn’t provide much explanation on how to use the framework. This article shows how to start using the Get framework in your apps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;basicworkflow&#34;&gt;Basic Workflow&lt;/h3&gt;&#xA;&lt;p&gt;Using the Get framework involves the following basic steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Create an API client instance&lt;/li&gt;&#xA;&lt;li&gt;Create a network request&lt;/li&gt;&#xA;&lt;li&gt;Send the request&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h4 id=&#34;createanapiclientinstance&#34;&gt;Create an API Client Instance&lt;/h4&gt;&#xA;&lt;p&gt;Get provides an &lt;code&gt;APIClient&lt;/code&gt; class for API clients. Create an instance, supplying the base URL to the network API you want to use. The following example creates an API client for the Jira REST API:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; client = APIClient(baseURL: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URL(string: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://api.atlassian.com&amp;#34;&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;createanetworkrequest&#34;&gt;Create a Network Request&lt;/h4&gt;&#xA;&lt;p&gt;Get has a &lt;code&gt;Request&lt;/code&gt; struct that represents a network request. Fill the &lt;code&gt;Request&lt;/code&gt; struct to create a network request. The &lt;code&gt;Request&lt;/code&gt; struct has the following fields:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The body, which you use to send data from your app to the API. POST and PUT methods require you to supply a body.&lt;/li&gt;&#xA;&lt;li&gt;Headers for the request. The &lt;code&gt;headers&lt;/code&gt; field is a Swift dictionary where each key and value are strings.&lt;/li&gt;&#xA;&lt;li&gt;An ID for the request. You probably won’t need to set an ID.&lt;/li&gt;&#xA;&lt;li&gt;The method, such as GET, POST, or PUT.&lt;/li&gt;&#xA;&lt;li&gt;Query items. The &lt;code&gt;query&lt;/code&gt; field is an array of Swift tuples, consisting of two strings.&lt;/li&gt;&#xA;&lt;li&gt;The URL for the network call.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The Get framework defaults to using GET methods and leaving the other fields blank so the only fields you have to fill are the ones you need to make the network call.&lt;/p&gt;&#xA;&lt;p&gt;To create a request for a GET method, start by creating a variable of type &lt;code&gt;Request&lt;/code&gt;. Place the data type you want to return in angle brackets and supply the URL for the network call.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; request = Request&amp;lt;T&amp;gt;(url: urlPath)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace &lt;code&gt;T&lt;/code&gt; with the type you want to return from the network call. Replace &lt;code&gt;urlPath&lt;/code&gt; with the URL string for the API call to make.&lt;/p&gt;&#xA;&lt;p&gt;After creating the request, fill the fields your network call requires.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;request.headers =  [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Accept&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Sort results alphabetically&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;request.query = [(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;orderBy&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;)]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you have a method that sends data to the server, such as a POST or PUT method, you must create the body data and supply it when creating the request. The &lt;code&gt;body&lt;/code&gt; property is a let constant so you can’t set the body after creating the request.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; request = Request&amp;lt;T&amp;gt;(url: urlPath, body: bodyData)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;request.method = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;request.headers =  [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Accept&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The body must conform to the &lt;code&gt;Encodable&lt;/code&gt; protocol.&lt;/p&gt;&#xA;&lt;h4 id=&#34;sendingtherequest&#34;&gt;Sending the Request&lt;/h4&gt;&#xA;&lt;p&gt;The API client has a &lt;code&gt;send&lt;/code&gt; method to send the network request. Supply the request.&lt;/p&gt;&#xA;&lt;p&gt;Usually a network call returns data. By attaching the &lt;code&gt;value&lt;/code&gt; property when sending the request, you will get decoded data back in the type you specified when creating the request.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; await client.send(request).value&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You’re going to use this code a lot when using Get. In one line of code you can send a network request and get data back in a form that your app can use.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Saving Passwords in the Keychain in Swift</title>
      <link>https://swiftdevjournal.com/saving-passwords-in-the-keychain-in-swift/</link>
      <pubDate>Tue, 12 Jul 2022 18:29:42 +0000</pubDate>
      <guid>https://swiftdevjournal.com/saving-passwords-in-the-keychain-in-swift/</guid>
      <description>&lt;p&gt;The Keychain is the place to store small amounts of data securely, such as passwords and API tokens. In this article you’ll learn how to work with the Keychain in iOS and Mac apps using the Keychain Services framework.&lt;/p&gt;&#xA;&lt;h3 id=&#34;partsofakeychainaction&#34;&gt;Parts of a Keychain Action&lt;/h3&gt;&#xA;&lt;p&gt;There are four common actions to perform on keychain items: add an item, update an item, read an item, and delete an item. To perform a keychain action, create a query and run a Keychain Services function.&lt;/p&gt;&#xA;&lt;h4 id=&#34;query&#34;&gt;Query&lt;/h4&gt;&#xA;&lt;p&gt;A query tells Keychain Services what you want to do. A query is a Swift dictionary that you must cast to &lt;code&gt;CFDictionary&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Every query must include an entry with the key &lt;code&gt;kSecClass&lt;/code&gt;, which specifies the kind of item to add, update, read, or delete. There are the following Keychain item types:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Generic password, &lt;code&gt;kSecClassGenericPassword&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Internet password, &lt;code&gt;kSecClassInternetPassword&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Certificate, &lt;code&gt;kSecClassCertificate&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Cryptographic key item, &lt;code&gt;kSecClassKey&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Identity item, &lt;code&gt;kSecClassIdentity&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I’m going to focus on generic passwords in this article, as that’s what most apps use. You’re not limited to passwords when using generic passwords. I was able to use generic passwords to store OAuth tokens in the Keychain.&lt;/p&gt;&#xA;&lt;p&gt;The query keys you can use depend on the class. You can find a list of possible keys in the following section of Apple’s documentation:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_class_keys_and_values&#34;&gt;Item Class Keys and Values&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the link for a class to see the available items. You can also read the documentation in Xcode by choosing Help &amp;gt; Developer Documentation.&lt;/p&gt;&#xA;&lt;p&gt;Two common item attributes for generic passwords are services, &lt;code&gt;kSecAttrService&lt;/code&gt;, and accounts, &lt;code&gt;kSecAttrAccount&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The value you supply for the service is the text that appears for the item in the Keychain Access app on Mac. Make sure the text clearly shows the keychain item is part of your app. A generic value like &lt;code&gt;password&lt;/code&gt; will be hard to find in the Keychain Access app.&lt;/p&gt;&#xA;&lt;p&gt;The value for the account is the name of the password’s account. If you’re writing a Mastodon client, &lt;code&gt;Mastodon&lt;/code&gt; would be a good value for the account.&lt;/p&gt;&#xA;&lt;h4 id=&#34;keychainservicesfunctions&#34;&gt;Keychain Services Functions&lt;/h4&gt;&#xA;&lt;p&gt;Call the following functions to work with the Keychain for passwords:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;SecItemAdd&lt;/code&gt; to add an item to the Keychain&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;SecItemUpdate&lt;/code&gt; to update an existing Keychain item&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;SecItemCopyMatching&lt;/code&gt; to read an item from the Keychain&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;SecItemDelete&lt;/code&gt; to delete an item from the Keychain&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;addingakeychainitem&#34;&gt;Adding a Keychain Item&lt;/h3&gt;&#xA;&lt;p&gt;Start by importing the Authentication Services framework. The Keychain Services API is in the Authentication Services framework.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AuthenticationServices&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should also create a class for the Keychain functions.&lt;/p&gt;&#xA;&lt;p&gt;Let’s start by writing a function to add an item to the Keychain.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;save&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; data: Data, service: String, account: String) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; query = [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecValueData: data,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecClass: kSecClassGenericPassword,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecAttrService: service,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecAttrAccount: account&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; CFDictionary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; saveStatus = SecItemAdd(query, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; saveStatus &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; errSecSuccess {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;saveStatus&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; saveStatus == errSecDuplicateItem {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    update(data, service: service, account: account)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function starts by building a query. Tell Keychain Services that you’re adding a generic password. Supply the data, service, and account. The data is what you want to save in the Keychain.&lt;/p&gt;&#xA;&lt;p&gt;After building the query, call the function &lt;code&gt;SecAddItem&lt;/code&gt; to add the item to the Keychain. If the item is added to the Keychain successfully, &lt;code&gt;SecAddItem&lt;/code&gt; returns the value &lt;code&gt;errSecSuccess&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;If the item already exists in the Keychain, &lt;code&gt;SecAddItem&lt;/code&gt; returns the value &lt;code&gt;errSecDuplicateItem&lt;/code&gt;. In this case update the existing item, which I cover next.&lt;/p&gt;&#xA;&lt;h3 id=&#34;updatinganexistingkeychainitem&#34;&gt;Updating an Existing Keychain Item&lt;/h3&gt;&#xA;&lt;p&gt;Let’s look at the code to update a keychain item.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; data: Data, service: String, account: String) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; query = [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecClass: kSecClassGenericPassword,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecAttrService: service,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecAttrAccount: account&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; CFDictionary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; updatedData = [kSecValueData: data] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; CFDictionary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  SecItemUpdate(query, updatedData)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that the &lt;code&gt;update&lt;/code&gt; function doesn’t include the data in the query. The code creates another dictionary for the data and passes it as an argument to the function &lt;code&gt;SecItemUpdate&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;readinganitemfromthekeychain&#34;&gt;Reading an Item from the Keychain&lt;/h3&gt;&#xA;&lt;p&gt;Saving items to the Keychain isn’t going to help unless your app can read the keychain items.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(service: String, account: String) -&amp;gt; Data? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; query = [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecClass: kSecClassGenericPassword,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecAttrService: service,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecAttrAccount: account,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecReturnData: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; CFDictionary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; result: AnyObject?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  SecItemCopyMatching(query, &amp;amp;result)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? Data&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The big difference in the query is the &lt;code&gt;kSecReturnData&lt;/code&gt; key, which tells Keychain Services you want to return data from the function call. The function &lt;code&gt;SecItemCopyMatching&lt;/code&gt; returns its results as type &lt;code&gt;AnyObject?&lt;/code&gt;. You saved the item as &lt;code&gt;Data&lt;/code&gt; so you should return a &lt;code&gt;Data&lt;/code&gt; object. If there is no matching item in the Keychain, &lt;code&gt;SecItemCopyMatching&lt;/code&gt; returns nil.&lt;/p&gt;&#xA;&lt;h3 id=&#34;deletinganitemfromthekeychain&#34;&gt;Deleting an Item from the Keychain&lt;/h3&gt;&#xA;&lt;p&gt;The last major task to perform on Keychain items is to delete items from the Keychain.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;delete&lt;/span&gt;(service: String, account: String) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; query = [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecClass: kSecClassGenericPassword,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecAttrService: service,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kSecAttrAccount: account&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; CFDictionary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  SecItemDelete(query)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The query for deleting an item is the simplest one. Supply the class, service, and account. Call &lt;code&gt;SecItemDelete&lt;/code&gt; to delete the item from the Keychain.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Intro to Making SwiftUI Apps with Swift Playgrounds</title>
      <link>https://swiftdevjournal.com/intro-to-making-swiftui-apps-with-swift-playgrounds/</link>
      <pubDate>Tue, 07 Jun 2022 17:40:42 +0000</pubDate>
      <guid>https://swiftdevjournal.com/intro-to-making-swiftui-apps-with-swift-playgrounds/</guid>
      <description>&lt;p&gt;The Swift Playgrounds app lets you create SwiftUI apps if you are using Swift Playgrounds 4 on an iPad running iOS 15 and above or a Mac running macOS 12.4 and above. In this article you’ll learn the basics of Swift Playgrounds. After reading this article you’ll be able to follow SwiftUI tutorials using Swift Playgrounds.&lt;/p&gt;&#xA;&lt;p&gt;The screenshots in this article are from the Mac version of Swift Playgrounds. But the iOS and Mac versions have a similar look.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createanappplayground&#34;&gt;Create an App Playground&lt;/h3&gt;&#xA;&lt;p&gt;When you launch Swift Playgrounds, a window opens for you to either create a playground or open an existing playground.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SwiftPlaygroundsStartWindow.png&#34; alt=&#34;Swift playgrounds start window&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Tap or click App from the More Playgrounds section to create an app playground. The app gives a generic name for the playground. Tap or click on the name to change the app name.&lt;/p&gt;&#xA;&lt;h3 id=&#34;theplaygroundwindow&#34;&gt;The Playground Window&lt;/h3&gt;&#xA;&lt;p&gt;When you open the playground, the playground window opens.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AppPlaygroundWindowHighlighted.png&#34; alt=&#34;app playground window&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The playground window has the following sections:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Sidebar&lt;/li&gt;&#xA;&lt;li&gt;Editor&lt;/li&gt;&#xA;&lt;li&gt;Console&lt;/li&gt;&#xA;&lt;li&gt;Preview&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The sidebar shows a list of files in the playground and a control to change the app settings.&lt;/p&gt;&#xA;&lt;p&gt;The editor is where you write code.&lt;/p&gt;&#xA;&lt;p&gt;The console shows output and error messages. If your code uses &lt;code&gt;print&lt;/code&gt; statements, the text in the &lt;code&gt;print&lt;/code&gt; statements appears in the console. The console is hidden initially. Tap or click the small button at the bottom of the window to toggle showing and hiding the console.&lt;/p&gt;&#xA;&lt;p&gt;The preview shows how the interface is going to look when you run the app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;changingappsettings&#34;&gt;Changing App Settings&lt;/h3&gt;&#xA;&lt;p&gt;Tap or click the App Settings item in the sidebar to change the app settings.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ChangeAppSettings.png&#34; alt=&#34;change app settings&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Use the Name text field to change the name of the app.&lt;/p&gt;&#xA;&lt;p&gt;Choose a color for the app icon from the Accent Color color picker. Use the view below the color picker to choose an image for the app icon.&lt;/p&gt;&#xA;&lt;p&gt;Use the Capabilities control to add app capabilities like giving the app access to things like the device’s camera, the user’s contacts, and the user’s media library.&lt;/p&gt;&#xA;&lt;p&gt;The Mac version has a button to install the app in the Applications folder.&lt;/p&gt;&#xA;&lt;h3 id=&#34;editingsourcecode&#34;&gt;Editing Source Code&lt;/h3&gt;&#xA;&lt;p&gt;Select a Swift file from the sidebar to open it in the editor and start coding. When you create an app playground Swift Playgrounds creates two files: a file for the app and a file for the content view. The app file creates a window whose main view is the content view. The content view file has the code for the views and controls inside the content view. The preview shows what the content view looks like.&lt;/p&gt;&#xA;&lt;p&gt;Clicking the Add button at the top of the window opens a popover that shows a list of SwiftUI controls and items you can add to your code.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SwiftUIControlsPopover.png&#34; alt=&#34;SwiftUI controls popover&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;SwiftUI has many items you can add so they’re broken up into four groups that have buttons below the search field. Selecting an item from the popover inserts code for that item in the editor.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addingfilestotheplayground&#34;&gt;Adding Files to the Playground&lt;/h3&gt;&#xA;&lt;p&gt;Virtually every app requires more files than the two source code files provided when you create an app playground. Swift Playgrounds lets you add the following items to a playground:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;New Swift files&lt;/li&gt;&#xA;&lt;li&gt;Existing files&lt;/li&gt;&#xA;&lt;li&gt;Folders to group files in the sidebar&lt;/li&gt;&#xA;&lt;li&gt;Swift packages that contain code libraries&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Compared to Xcode, Swift Playgrounds has limited options for adding files. If you’re following a SwiftUI tutorial that uses Xcode, you’ll run into problems if the tutorial adds new files that aren’t Swift files.&lt;/p&gt;&#xA;&lt;p&gt;The iOS version has an Add Document icon at the top of the sidebar. Tap the icon and choose what you want to add from the menu that opens.&lt;/p&gt;&#xA;&lt;p&gt;Use the File menu in the Mac version to add files to the playground. Choose File &amp;gt; New Source File to create a new Swift file. Choose File &amp;gt; Add File to add an existing file to the playground. Choose File &amp;gt; New Folder to add a folder to the sidebar. Choose File &amp;gt; Add Package to add a Swift package to the playground.&lt;/p&gt;&#xA;&lt;h3 id=&#34;runningtheapp&#34;&gt;Running the App&lt;/h3&gt;&#xA;&lt;p&gt;Tap or click the Run (Play) button at the top of the window to build and run the app. A newly created app playground should build with no errors.&lt;/p&gt;&#xA;&lt;p&gt;If there are errors in your code, the app won’t build and run. There will be a small button with a red X for any error in the code. Tap or click the button to see the error message.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SyntaxErrorMessage.png&#34; alt=&#34;syntax error message&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;readingdeveloperdocumentation&#34;&gt;Reading Developer Documentation&lt;/h3&gt;&#xA;&lt;p&gt;The iOS version has a button with a circle and three dots inside it. Tap that button and choose Documentation to read Apple’s developer documentation.&lt;/p&gt;&#xA;&lt;p&gt;Choose Help &amp;gt; Show Developer Documentation in the Mac version to read Apple’s developer documentation.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wheretogofromhere&#34;&gt;Where to go from here?&lt;/h3&gt;&#xA;&lt;p&gt;Check out the following WWDC video:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://developer.apple.com/videos/play/wwdc2022/110348/&#34;&gt;Build your first app in Swift Playgrounds&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Rija Development: Using OAuth Tokens to Make REST API Calls</title>
      <link>https://swiftdevjournal.com/rija-development-using-oauth-tokens-to-make-rest-api-calls/</link>
      <pubDate>Mon, 23 May 2022 17:50:17 +0000</pubDate>
      <guid>https://swiftdevjournal.com/rija-development-using-oauth-tokens-to-make-rest-api-calls/</guid>
      <description>&lt;p&gt;In my last &lt;a href=&#34;https://www.swiftdevjournal.com/rija-development-oauth-authorization/&#34;&gt;Rija development post&lt;/a&gt; I talked about getting an OAuth access token for Jira so other people can use Rija. This post covers using the access token to make calls to Jira’s REST API. You must perform the following tasks to make API calls with an OAuth token:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Get the user’s Jira cloud ID&lt;/li&gt;&#xA;&lt;li&gt;Get the URL for Jira’s REST APIs&lt;/li&gt;&#xA;&lt;li&gt;Add the access token to the authorization header&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;getuserscloudid&#34;&gt;Get User’s Cloud ID&lt;/h3&gt;&#xA;&lt;p&gt;Each Jira site has a unique cloud ID. You can’t make calls to Jira’s REST API with an OAuth token without the cloud ID for the user’s Jira site. The first thing you must do is get the cloud ID. To get the cloud ID, make a URL request to the following URL:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;https://api.atlassian.com/oauth/token/accessible-resources&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add the access token string to the authorization header. Run a URL session with the URL request. The following code retrieves a Jira cloud ID:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;retrieveCloudID&lt;/span&gt;() async -&amp;gt; String {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Build the URL    &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; components = URLComponents()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.scheme = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.host = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api.atlassian.com&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.path = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/oauth/token/accessible-resources&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; request = URLRequest(url: components.url!)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; accessToken = getAccessToken() &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Add the access token to the authorization header&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; authString = String(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Bearer &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;accessToken&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  request.addValue(authString, forHTTPHeaderField: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  request.addValue(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;, forHTTPHeaderField: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Retrieve the cloud ID&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; (data, error) = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; await URLSession.shared.data(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;: request, delegate: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; decoder = JSONDecoder()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; cloudDictionary = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; decoder.decode([JiraCloudID].&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      from: data)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; cloudDictionary.first?.id ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;JiraCloudID&lt;/code&gt; is a struct I created with the properties &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;url&lt;/code&gt;. The &lt;code&gt;id&lt;/code&gt; property contains the cloud ID.&lt;/p&gt;&#xA;&lt;h3 id=&#34;getjirasrestapiurl&#34;&gt;Get Jira’s REST API URL&lt;/h3&gt;&#xA;&lt;p&gt;Jira has a different URL for making API calls with an OAuth access token than they have for making calls with a personal access token. The base URL is the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;https://api.atlassian.com/ex/jira&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Append the cloud ID and the path to the REST API call you’re making.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addtheaccesstokentotheauthorizationheader&#34;&gt;Add the Access Token to the Authorization Header&lt;/h3&gt;&#xA;&lt;p&gt;I showed the code to add the access token in the code to retrieve the cloud ID. But let’s show it again.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; accessToken = getAccessToken() &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; authString = String(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Bearer &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;accessToken&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;request.addValue(authString, forHTTPHeaderField: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Jira’s REST API requires the string &lt;code&gt;Bearer&lt;/code&gt; followed by the access token string. Add the string to the URL request’s authorization header.&lt;/p&gt;&#xA;&lt;p&gt;If you read Apple’s documentation for the &lt;code&gt;URLRequest&lt;/code&gt; class, they tell you not to set the Authorization header manually because it’s a reserved header. But Apple provides no alternative to manually setting the header manually so I have to set the Authorization header manually.&lt;/p&gt;&#xA;&lt;h3 id=&#34;anexampleapicall&#34;&gt;An Example API Call&lt;/h3&gt;&#xA;&lt;p&gt;The following code fetches someone’s Jira projects:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fetchProjects&lt;/span&gt;() async &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; JiraProjectList {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; cloudID = await getCloudID()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Build the URL &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; components = URLComponents()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.scheme = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.host = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api.atlassian.com&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.path = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/ex/jira/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; cloudID &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/rest/api/3/project/search&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Sort projects alphabetically by default&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.queryItems = [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;orderBy&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; request = URLRequest(url: components.url!)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// JiraProjectList contains an array of projects.   &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; accessToken = getAccessToken() &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; JiraProjectList()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Add access token to authorization.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; authString = String(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Bearer &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;accessToken&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  request.addValue(authString, forHTTPHeaderField: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  request.addValue(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;, forHTTPHeaderField: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; (data, error) = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; await URLSession.shared.data(&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    request, delegate: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; decoder = JSONDecoder()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; decoder.decode(JiraProjectList.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;, from: data)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I start by building the URL. I want to sort the projects alphabetically so I supply a URL query item. Then I add the access token to the authorization header. Finally I run the URL request.&lt;/p&gt;&#xA;&lt;p&gt;Jira’s REST API returns the projects in a dictionary instead of an array. I have to create a &lt;code&gt;JiraProjectList&lt;/code&gt; struct to decode the JSON properly. All the struct contains is an array of projects.&lt;/p&gt;&#xA;&lt;h3 id=&#34;aboutrija&#34;&gt;About Rija&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.checksimsoftware.com/rija/&#34;&gt;Rija&lt;/a&gt; is a Jira issue tracker under development for Mac (and possibly iOS). The following article provides more details on Rija:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/rija-development-intro/&#34;&gt;Rija Development: Intro&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Log in to Websites with ASWebAuthenticationSession</title>
      <link>https://swiftdevjournal.com/log-in-to-websites-with-aswebauthenticationsession/</link>
      <pubDate>Wed, 11 May 2022 17:52:38 +0000</pubDate>
      <guid>https://swiftdevjournal.com/log-in-to-websites-with-aswebauthenticationsession/</guid>
      <description>&lt;h3 id=&#34;whatisaswebauthenticationsession&#34;&gt;What is ASWebAuthenticationSession?&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; is a class in Apple’s Authentication Services framework that simplifies logging into websites from iOS and Mac apps. When you create and start an instance of &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt;, a private browser window opens for someone to sign into a website.&lt;/p&gt;&#xA;&lt;p&gt;When would you use &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt;? Use it if your app needs to log into a website. Suppose you’re writing a Twitter app like Tweetbot or Twitterific. The first time someone launches your app, they need to sign into Twitter so they can use your app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addacustomurltypeforyourapp&#34;&gt;Add a Custom URL Type for Your App&lt;/h3&gt;&#xA;&lt;p&gt;When someone finishes logging in to the website, they should go back to your app. You must add a URL type to your app to go back to the app.&lt;/p&gt;&#xA;&lt;p&gt;Select your app target from the project editor and click the Info button at the top to add a URL type to the app.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CustomURLType.png&#34; alt=&#34;custom URL type&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Give your URL type a name in the Identifier text field. Enter the URL type in the URL Schemes text field. The type should take the following form:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;appname://&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;createaclassfortheloginsession&#34;&gt;Create a Class for the Login Session&lt;/h3&gt;&#xA;&lt;p&gt;To use &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; you must add a class to hold the login session.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AuthenticationServices&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LoginSession&lt;/span&gt;: NSObject, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ObservableObject, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ASWebAuthenticationPresentationContextProviding {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; webAuthSession: ASWebAuthenticationSession?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; class is part of the Authentication Services framework so you must import that framework.&lt;/p&gt;&#xA;&lt;p&gt;The class must conform to the &lt;code&gt;ASWebAuthenticationPresentationContextProviding&lt;/code&gt; protocol. Inheriting from &lt;code&gt;NSObject&lt;/code&gt; is the easiest way to conform to the protocol. Conforming to &lt;code&gt;ObservableObject&lt;/code&gt; isn’t mandatory, but it helps for SwiftUI apps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addapresentationanchor&#34;&gt;Add a Presentation Anchor&lt;/h3&gt;&#xA;&lt;p&gt;The login session requires a presentation anchor, which is a window to show the login session.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;presentationAnchor&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; session: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ASWebAuthenticationSession) -&amp;gt; ASPresentationAnchor {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ASPresentationAnchor()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ASPresentationAnchor&lt;/code&gt; is an instance of &lt;code&gt;UIWindow&lt;/code&gt; on iOS and an instance of &lt;code&gt;NSWindow&lt;/code&gt; on Mac.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createanaswebauthenticationsessioninstance&#34;&gt;Create an ASWebAuthenticationSession Instance&lt;/h3&gt;&#xA;&lt;p&gt;Now you can create an instance of &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt;. You must supply the following arguments:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The URL of the website to log in.&lt;/li&gt;&#xA;&lt;li&gt;The callback URL, the URL to go when the login session finishes.&lt;/li&gt;&#xA;&lt;li&gt;A completion handler closure (function) that runs when the session finishes successfully.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The callback URL is the custom URL type you created for the app, minus the &lt;code&gt;://&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;appname&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The code looks like the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webAuthSession = ASWebAuthenticationSession.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  url: websiteURL, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  callbackURLScheme: callbackUrl, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  completionHandler: { (callback:URL?, error:Error?) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Do what you need to after someone logs in.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Run the session&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webAuthSession?.presentationContextProvider = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webAuthSession?.prefersEphemeralWebBrowserSession = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webAuthSession?.start()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should use ephemeral web browser sessions. If you set &lt;code&gt;prefersEphemeralWebBrowserSession&lt;/code&gt; to false, information from previous sessions will be available in the session.&lt;/p&gt;&#xA;&lt;p&gt;If you need to make any async calls in the completion handler, wrap them in a &lt;code&gt;Task&lt;/code&gt; block. &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; does not support Swift’s &lt;code&gt;async await&lt;/code&gt; concurrency features.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Task {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Put async calls here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see an example of using &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; to sign in to Jira’s website in the following article:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/rija-development-oauth-authorization/&#34;&gt;Rija Development: OAuth Authorization&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Rija Development: OAuth Authorization</title>
      <link>https://swiftdevjournal.com/rija-development-oauth-authorization/</link>
      <pubDate>Fri, 06 May 2022 17:52:19 +0000</pubDate>
      <guid>https://swiftdevjournal.com/rija-development-oauth-authorization/</guid>
      <description>&lt;h3 id=&#34;authorizationflow&#34;&gt;Authorization Flow&lt;/h3&gt;&#xA;&lt;p&gt;When someone launches &lt;a href=&#34;https://www.checksimsoftware.com/rija/&#34;&gt;Rija&lt;/a&gt; for the first time, Rija must get a Jira access token that gives the app access to the person’s Jira account. This involves the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Show a login view with a button to sign in to Jira.&lt;/li&gt;&#xA;&lt;li&gt;When the person clicks the button, a private browser opens.&lt;/li&gt;&#xA;&lt;li&gt;The person signs in to their Jira account.&lt;/li&gt;&#xA;&lt;li&gt;The person grants Rija permission to access their Jira account.&lt;/li&gt;&#xA;&lt;li&gt;Jira gives Rija an authorization code.&lt;/li&gt;&#xA;&lt;li&gt;Rija exchanges the authorization code for the access token.&lt;/li&gt;&#xA;&lt;li&gt;Rija saves the access token in the Keychain.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;This post is going to focus on Steps 3–6.&lt;/p&gt;&#xA;&lt;h3 id=&#34;signintojirawithaswebauthenticationsession&#34;&gt;Sign in to Jira with ASWebAuthenticationSession&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; class simplifies logging into websites from Swift apps. To create a login session, create a &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; object and supply three arguments:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;An authorization URL&lt;/li&gt;&#xA;&lt;li&gt;A callback URL&lt;/li&gt;&#xA;&lt;li&gt;A callback closure&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;When the login session finishes successfully, the code in the callback closure runs.&lt;/p&gt;&#xA;&lt;h4 id=&#34;authorizationurl&#34;&gt;Authorization URL&lt;/h4&gt;&#xA;&lt;p&gt;The authorization URL is the URL for the website where you’re logging in. Jira has the following URL for OAuth authorization:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;https://auth.atlassian.com/authorize?&#xA;  audience=api.atlassian.com&amp;amp;&#xA;  client_id=YOUR_CLIENT_ID&amp;amp;&#xA;  scope=REQUESTED_SCOPE_ONE%20REQUESTED_SCOPE_TWO&amp;amp;&#xA;  redirect_uri=https://YOUR_APP_CALLBACK_URL&amp;amp;&#xA;  state=YOUR_USER_BOUND_VALUE&amp;amp;&#xA;  response_type=code&amp;amp;&#xA;  prompt=consent&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I use the following code to set the URL to sign in to Jira:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; components = URLComponents()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;components.scheme = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;components.host = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;auth.atlassian.com&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;components.path = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/authorize&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;components.queryItems = [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;audience&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api.atlassian.com&amp;#34;&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;client_id&amp;#34;&lt;/span&gt;, value: clientID),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;scope&amp;#34;&lt;/span&gt;, value: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;read:jira-user &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    read:jira-work &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    manage:jira-configuration &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    manage:jira-project &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    write:jira-work &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    offline_access&amp;#34;&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;redirect_uri&amp;#34;&lt;/span&gt;, value: callbackUrl &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;://auth&amp;#34;&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;state&amp;#34;&lt;/span&gt;, value: UUID().uuidString),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;response_type&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;prompt&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;consent&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; authURL = components.url &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Jira’s authorization URL is complex, as you can see by the amount of code needed to build the URL.&lt;/p&gt;&#xA;&lt;h4 id=&#34;callbackurl&#34;&gt;Callback URL&lt;/h4&gt;&#xA;&lt;p&gt;The callback URL is where you go when the login session finishes. For iOS and Mac apps the callback URL should take you back to the app.&lt;/p&gt;&#xA;&lt;p&gt;Creating a callback URL requires you to add a custom URL type to your &lt;code&gt;Info.plist&lt;/code&gt; file.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CustomURLType.png&#34; alt=&#34;custom URL type&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter the URL type in the URL Schemes text field. It should look like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;appname://&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But when you supply the callback URL for the login session, you should omit the &lt;code&gt;://&lt;/code&gt; part of the URL. &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; cannot handle colons in the callback URL.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; callbackUrl = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rija&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;theaswebauthenticationsessioncode&#34;&gt;The ASWebAuthenticationSession Code&lt;/h4&gt;&#xA;&lt;p&gt;Using Apple’s &lt;code&gt;ASWebAuthenticationSession&lt;/code&gt; class simplifies signing in to websites. The following code initializes and starts the login session:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; webAuthSession: ASWebAuthenticationSession?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webAuthSession = ASWebAuthenticationSession.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(url: authURL,  callbackURLScheme: callbackUrl, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  completionHandler: { (callback:URL?, error:Error?) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; error == &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; successURL = callback &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Get the authorization code.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; query = URLComponents(string: (successURL.absoluteString))?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .queryItems?.filter({$0.name == &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;}).first&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; authorizationCode = query?.value ?? &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Exchange the authorization code for an access token and save it &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// in the Keychain. I have to make the calls inside the &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// callback to ensure there&amp;#39;s a valid authorization &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// code before doing anything else.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Have to wrap the code in a Task block because &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// ASWebAuthenticationSession does not &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// support Swift concurrency (async await).&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Task {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; token = await &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.exchangeAuthorizationCodeFor&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      AccessToken(code: authorizationCode) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.saveTokenInKeychain(token: token)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Run the session&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webAuthSession?.presentationContextProvider = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webAuthSession?.prefersEphemeralWebBrowserSession = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;webAuthSession?.start()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following article has more details on login sessions:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/log-in-to-websites-with-aswebauthenticationsession/&#34;&gt;Log in to Websites with ASWebAuthenticationSession&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;exchangetheauthorizationcodefortheaccesstoken&#34;&gt;Exchange the Authorization Code for the Access Token&lt;/h3&gt;&#xA;&lt;p&gt;After getting the authorization code from Jira, you have to exchange the code for an access token, which you use to make REST API calls in Jira. The exchange involves making a POST request to Jira, supplying the authorization code as part of the body. The following code demonstrates how to exchange the authorization code for an access token:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;exchangeForAccessToken&lt;/span&gt;(authorizationCode: String) async -&amp;gt; AuthToken? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; components = URLComponents()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.scheme = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.host = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;auth.atlassian.com&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  components.path = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/oauth/token&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; request = URLRequest(url: components.url!)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  request.addValue(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;, forHTTPHeaderField: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; clientID = ProcessInfo.processInfo.environment[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CLIENT_ID&amp;#34;&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; clientSecret = ProcessInfo.processInfo.environment[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CLIENT_SECRET&amp;#34;&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  request.httpMethod = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; body = [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;grant_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;authorization_code&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;client_id&amp;#34;&lt;/span&gt;: clientID,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;client_secret&amp;#34;&lt;/span&gt;: clientSecret,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: authorizationCode,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;redirect_uri&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rija://auth&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; bodyData = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;? JSONSerialization.data(withJSONObject: body)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  request.httpBody = bodyData&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; (data, error) = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; await URLSession.shared.data(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;: request, delegate: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; decoder = JSONDecoder()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; decoder.decode(AuthToken.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;, from: data)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(error)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;aboutrija&#34;&gt;About Rija&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.checksimsoftware.com/rija/&#34;&gt;Rija&lt;/a&gt; is a Jira issue tracker under development for Mac (and possibly iOS). The following article provides more details on Rija:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/rija-development-intro/&#34;&gt;Rija Development: Intro&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Rija Development: Using Jira’s REST APIs</title>
      <link>https://swiftdevjournal.com/rija-development-using-jiras-rest-apis/</link>
      <pubDate>Mon, 02 May 2022 17:52:34 +0000</pubDate>
      <guid>https://swiftdevjournal.com/rija-development-using-jiras-rest-apis/</guid>
      <description>&lt;p&gt;Developing &lt;a href=&#34;https://www.checksimsoftware.com/rija/&#34;&gt;Rija&lt;/a&gt; has me spending a lot of time working with Jira’s REST APIs. This post details some issues I have run into when working with the APIs.&lt;/p&gt;&#xA;&lt;h3 id=&#34;therestapiwrapsarraysindictionaries&#34;&gt;The REST API Wraps Arrays in Dictionaries&lt;/h3&gt;&#xA;&lt;p&gt;In GitHub’s API, if you want to get someone’s repositories or the issues for a given repository, you make the API call, and GitHub gives you an array of repositories or issues.&lt;/p&gt;&#xA;&lt;p&gt;But Jira’s REST API does not work like GitHub’s. When you make an API call to get a Jira account’s projects, the API returns a dictionary. The array that has the projects is one of the fields in the dictionary.&lt;/p&gt;&#xA;&lt;p&gt;Wrapping the array inside a dictionary makes decoding the JSON difficult. I kept getting errors saying I was trying to decode an array but the JSON was a dictionary. I had to create new data structures that contained an array of what I what I wanted to get the JSON decoding to work.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JiraProjectList&lt;/span&gt;: Codable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; projects: [Project]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CodingKeys&lt;/span&gt;: String, CodingKey {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; projects = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;values&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    projects = []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(from decoder: Decoder) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; valueContainer = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; decoder.container(keyedBy: CodingKeys.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.projects = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; valueContainer.decode([Project].&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      forKey: CodingKeys.projects)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;youhavetousejqltofetchmultipleissues&#34;&gt;You have to Use JQL to Fetch Multiple Issues&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/&#34;&gt;Jira’s REST API&lt;/a&gt; does not provide a call to get multiple issues. If you want to do something like fetch a list of a project’s issues or the issues assigned to a person, you have to use JQL, Jira’s query language. You have to build a URL string to make a query.&lt;/p&gt;&#xA;&lt;p&gt;Fortunately the Foundation framework has &lt;code&gt;URLComponents&lt;/code&gt; to make building a URL safer. Here’s the code I had to write to set up JQL to retrieve a selected project’s issues.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; projectString = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;project = &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; project.key&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; components = URLComponents()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;components.scheme = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;components.host = domain &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.atlassian.net&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;components.path = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/rest/api/3/search&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;components.queryItems = [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;jql&amp;#34;&lt;/span&gt;, value: projectString),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  URLQueryItem(name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fields&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;issue,summary,description&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;atlassiandocumentformat&#34;&gt;Atlassian Document Format&lt;/h3&gt;&#xA;&lt;p&gt;The latest version of Jira’s REST API changed the data type for an issue’s description and its comments. Instead of returning a string, the API returns the description and comments in &lt;a href=&#34;https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/&#34;&gt;Atlassian Document Format&lt;/a&gt;. Atlassian Document Format is a JSON format that provides support for headings, code blocks, lists, bold text, and italic text.&lt;/p&gt;&#xA;&lt;p&gt;The problem I ran into is that most of the examples I found on working with issue descriptions and comments used the old API version that returns strings. There aren’t many examples on using Atlassian Document Format.&lt;/p&gt;&#xA;&lt;p&gt;Early versions of Rija are going to treat everything as a paragraph. Supporting Markdown is a nice to have feature for a future version. Write in Markdown in Rija and have the text in Atlassian Document Format in Jira.&lt;/p&gt;&#xA;&lt;h2 id=&#34;aboutrija&#34;&gt;About Rija&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.checksimsoftware.com/rija/&#34;&gt;Rija&lt;/a&gt; is a Jira issue tracker under development for Mac (and possibly iOS). The following article provides more details on Rija:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/rija-development-intro/&#34;&gt;Rija Development: Intro&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Rija Development: Intro</title>
      <link>https://swiftdevjournal.com/rija-development-intro/</link>
      <pubDate>Mon, 25 Apr 2022 18:46:04 +0000</pubDate>
      <guid>https://swiftdevjournal.com/rija-development-intro/</guid>
      <description>&lt;p&gt;I have started developing &lt;a href=&#34;https://www.checksimsoftware.com/rija/&#34;&gt;Rija&lt;/a&gt;, a native Mac (and possibly iOS) app for tracking issues in &lt;a href=&#34;https://www.atlassian.com/software/jira&#34;&gt;Jira&lt;/a&gt;. I’m experimenting with developing in the open. While I was creating a Twitter thread on developing Rija, I realized there are technical details that might interest other developers that won’t fit a tweet.&lt;/p&gt;&#xA;&lt;p&gt;This post is the first in a series of posts detailing Rija’s development journey. Future posts are going to be more technical than this one.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whyamimakingrija&#34;&gt;Why am I Making Rija?&lt;/h3&gt;&#xA;&lt;p&gt;I used &lt;a href=&#34;https://www.neat.io/bee/&#34;&gt;Bee&lt;/a&gt;, a Mac issue tracking app that worked with Jira and GitHub issues. The developer stopped developing Bee. I remember some people were upset about the news. I didn’t think much about it and moved on to doing issue tracking online and using text files on my Mac.&lt;/p&gt;&#xA;&lt;p&gt;Then I saw &lt;a href=&#34;https://community.atlassian.com/t5/Jira-Mobile-Apps-articles/Announcement-Sunsetting-the-Jira-Cloud-for-Mac-App/ba-p/1911778&#34;&gt;Atlassian announced they were stopping development of their Mac Jira app&lt;/a&gt;. People were disappointed to hear this news.&lt;/p&gt;&#xA;&lt;p&gt;After doing some more research I learned people hated using Jira’s website. The website is slow and uses lots of RAM. The website does not support Dark Mode. I saw numerous complaints about the difficulty of figuring out how to do things on Jira’s website.&lt;/p&gt;&#xA;&lt;p&gt;I realized I could help people by making a native Mac app for Jira. A native app would be faster than the website and use less RAM. A native app supports both Light and Dark modes. Developers wouldn’t need to have a browser tab open for hours at a time and wouldn’t have to worry about mistakenly closing the tab. Issue tracking is the area where developers spend the most time on Jira so I should focus on that first.&lt;/p&gt;&#xA;&lt;h3 id=&#34;rijastechnologystack&#34;&gt;Rija’s Technology Stack&lt;/h3&gt;&#xA;&lt;p&gt;I’m using SwiftUI to make Jira. By using SwiftUI I can make Rija run on both Mac and iOS. I’m focusing on the Mac version first because Atlassian stopped making a Mac app and continue to develop an iOS app for Jira.&lt;/p&gt;&#xA;&lt;h3 id=&#34;rijascurrentdevelopmentstatus&#34;&gt;Rija’s Current Development Status&lt;/h3&gt;&#xA;&lt;p&gt;Rija is in the very early stages of development. I wanted to know if I could work with Jira’s REST APIs in a Mac app. I was able to get a list of projects, a list of issues for a project, and show an issue’s summary and details using my Jira account.&lt;/p&gt;&#xA;&lt;p&gt;The next step in Rija’s development is to get the app to work for anyone with a Jira account. That’s what I’m working on right now.&lt;/p&gt;&#xA;&lt;p&gt;If you are interested in trying Rija when it’s ready for me to show to other people, go to the &lt;a href=&#34;https://www.checksimsoftware.com/rija/&#34;&gt;Rija page&lt;/a&gt; and click the Send Feedback button.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Dealing with “Failed to prepare device for development” Error Message in Xcode</title>
      <link>https://swiftdevjournal.com/dealing-with-failed-to-prepare-device-for-development-error-message-in-xcode/</link>
      <pubDate>Fri, 25 Mar 2022 18:56:19 +0000</pubDate>
      <guid>https://swiftdevjournal.com/dealing-with-failed-to-prepare-device-for-development-error-message-in-xcode/</guid>
      <description>&lt;p&gt;You update your iOS device to the latest version of iOS. Now you try to run your Xcode project on that device. An alert pops up in Xcode with the message &lt;code&gt;Failed to prepare device for development&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whyareyougettingthismessage&#34;&gt;Why Are You Getting This Message?&lt;/h3&gt;&#xA;&lt;p&gt;You are getting the &lt;code&gt;Failed to prepare device for development&lt;/code&gt; message because the device is running a newer version of iOS than Xcode supports.&lt;/p&gt;&#xA;&lt;p&gt;Each version of Xcode ships with a version of the iOS SDK. The &lt;a href=&#34;https://xcodereleases.com&#34;&gt;Xcode Releases&lt;/a&gt; site has a list of each version of Xcode along with the iOS SDK. The version of the SDK is the latest version of iOS that version of Xcode supports. You won’t be able to run your Xcode project on a device running a newer version of iOS.&lt;/p&gt;&#xA;&lt;p&gt;For example Xcode 13.2.1 ships with the iOS 15.2 SDK. If you are running Xcode 13.2.1, you won’t be able to run your project on a device running anything newer than iOS 15.2. If you have a device running iOS 15.4, you won’t be able to run the project on that device with Xcode 13.2.1.&lt;/p&gt;&#xA;&lt;h3 id=&#34;howdoyoufixtheerror&#34;&gt;How Do You Fix the Error?&lt;/h3&gt;&#xA;&lt;p&gt;The easiest solution is to install the latest version of Xcode. The latest version of Xcode has the latest version of the iOS SDK so you’ll be able to run and debug your project on a device running the latest version of iOS.&lt;/p&gt;&#xA;&lt;p&gt;If your Mac is running an older version of macOS, you might not be able to update to the latest version of Xcode. Xcode 13.3 requires macOS 12. If your Mac is running macOS 11 and can’t run macOS 12, you won’t be able to update to Xcode 13.3. What do you do then?&lt;/p&gt;&#xA;&lt;p&gt;There are two workarounds. The first is to &lt;a href=&#34;https://github.com/filsv/iPhoneOSDeviceSupport&#34;&gt;download iOS support files for the newer iOS version&lt;/a&gt; and copy them to your Xcode app bundle.&lt;/p&gt;&#xA;&lt;p&gt;The second workaround is to deselect the Debug executable checkbox in the Run step of the scheme. After the app launches, attach it to the debugger. The following article provides details and screenshots:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://hybridcattt.com/blog/debugging-on-latest-ios-with-older-xcode&#34;&gt;Debugging on iOS 15 with Xcode 12&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;ios17update&#34;&gt;iOS 17 Update&lt;/h4&gt;&#xA;&lt;p&gt;Starting with iOS 17 Apple no longer includes iOS support files so the first workaround won’t work. According to the following Stack Overflow question:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://stackoverflow.com/questions/76412754/how-to-run-on-ios-17-device-using-xcode-14&#34;&gt;How to run on iOS 17 Device using Xcode 14&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;The solution is to run the following command in the Terminal and restart Xcode:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;defaults write com.apple.dt.Xcode DVTEnableCoreDevice enabled&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;turnoffautomaticupdatesonyourdevice&#34;&gt;Turn off Automatic Updates on Your Device&lt;/h3&gt;&#xA;&lt;p&gt;Keeping up with the latest version of iOS requires using the latest version of Xcode. Xcode takes a long time to install. If you don’t want to be constantly updating Xcode, turn off automatic updates on your iOS device.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Why Won’t My Xcode Project Build?</title>
      <link>https://swiftdevjournal.com/why-wont-my-xcode-project-build/</link>
      <pubDate>Wed, 23 Mar 2022 19:58:02 +0000</pubDate>
      <guid>https://swiftdevjournal.com/why-wont-my-xcode-project-build/</guid>
      <description>&lt;p&gt;It’s frustrating to click the Run button in Xcode and find that your project won’t build and run. Xcode initially shows you a message like &lt;code&gt;Command CompileSwiftSources failed with a nonzero exit code&lt;/code&gt;, which really doesn’t help much. How do you find where the error is so you can fix it and run your project?&lt;/p&gt;&#xA;&lt;h3 id=&#34;getalistoftheerrors&#34;&gt;Get a List of the Errors&lt;/h3&gt;&#xA;&lt;p&gt;The first step to figuring out why your project won’t build is to find the compiler errors in your project. Open Xcode’s issue navigator by pressing Cmd–5.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/IssueNavigator.png&#34; alt=&#34;issue navigator&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The issue navigator shows the compiler errors in your project. Select an error to show the line where the error is.&lt;/p&gt;&#xA;&lt;h3 id=&#34;seeingmoredetailedinformationaboutanerror&#34;&gt;Seeing More Detailed Information about an Error&lt;/h3&gt;&#xA;&lt;p&gt;To see more detailed information about a compiler error, open the report navigator by pressing Cmd–9. Select a build from the report navigator to see the build steps and errors for that specific build.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ReportNavigatorHighlighted.png&#34; alt=&#34;report navigator&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the Log button (the small button with the horizontal lines) to see a detailed log of that particular build step.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tipsforfixingerrors&#34;&gt;Tips for Fixing Errors&lt;/h3&gt;&#xA;&lt;p&gt;You found the compiler errors in your project. How do you fix them?&lt;/p&gt;&#xA;&lt;p&gt;I can’t tell you specifically how to fix the errors because I can’t see your code. But I have some general tips to help you fix the compiler errors in your Xcode projects.&lt;/p&gt;&#xA;&lt;h4 id=&#34;makesureargumenttypesmatch&#34;&gt;Make Sure Argument Types Match&lt;/h4&gt;&#xA;&lt;p&gt;When calling functions, make sure the data types for the function arguments match. When the argument types don’t match, you get a compiler error message like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Can’t convert value of type X to expected argument type Y&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where &lt;code&gt;X&lt;/code&gt; and &lt;code&gt;Y&lt;/code&gt; data types.&lt;/p&gt;&#xA;&lt;p&gt;If a function takes an integer as the first argument and you pass a string, you’re going to get the &lt;code&gt;Can&#39;t convert value&lt;/code&gt; compiler error.&lt;/p&gt;&#xA;&lt;h4 id=&#34;checkfortypos&#34;&gt;Check for Typos&lt;/h4&gt;&#xA;&lt;p&gt;If I make a typographical error in this article, you’ll still be able to read the article. But if you make one small typo in your code, the project won’t build.&lt;/p&gt;&#xA;&lt;p&gt;Make sure you spell function names correctly when calling them. If you have a function called &lt;code&gt;doSomething&lt;/code&gt; and you call it like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;doSomethng()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You are going to get a compiler error because you made a typo when calling the function. There is no &lt;code&gt;doSomethng&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;p&gt;Make sure that you spell variable names correctly when accessing them. If you have a &lt;code&gt;player&lt;/code&gt; variable in your app and misspell it,&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;move(playr)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You are going to get a compiler error because there is no &lt;code&gt;playr&lt;/code&gt; variable.&lt;/p&gt;&#xA;&lt;p&gt;Make sure each left brace, bracket, parenthesis, and quotation mark has a matching right one. An extra left or right brace can lead to compiler errors with bizarre messages.&lt;/p&gt;&#xA;&lt;h4 id=&#34;importmissingmodules&#34;&gt;Import Missing Modules&lt;/h4&gt;&#xA;&lt;p&gt;Make sure you import the modules for the frameworks your app uses. If you’re writing an app that works with PDF documents, you must import the PDFKit framework to call its functions in your app.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PDFKit&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Document Types in SwiftUI Apps</title>
      <link>https://swiftdevjournal.com/document-types-in-swiftui-apps/</link>
      <pubDate>Fri, 14 Jan 2022 19:24:13 +0000</pubDate>
      <guid>https://swiftdevjournal.com/document-types-in-swiftui-apps/</guid>
      <description>&lt;p&gt;SwiftUI supports making document-based apps that let people create and save documents. To ensure the documents have the right file extension and save and load correctly, you must configure the app’s document types. There’s not much information online about document types in SwiftUI apps so I’m sharing what I learned in this article.&lt;/p&gt;&#xA;&lt;h3 id=&#34;accessingthedocumenttypesettings&#34;&gt;Accessing the Document Type Settings&lt;/h3&gt;&#xA;&lt;p&gt;Take the following steps to access the document type settings for your SwiftUI project:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Select the project file from the left side of Xcode’s project window to open the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Select your app from the target list on the left side of the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Click the Info button at the top of the project editor.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DocumentTypeSettings.png&#34; alt=&#34;open with text editor panel&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;There are three sections of document type settings.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Document Types&lt;/li&gt;&#xA;&lt;li&gt;Exported Type Identifiers&lt;/li&gt;&#xA;&lt;li&gt;Imported Type Identifiers&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A new SwiftUI document-based app project gives you a plain text editor. Unless you’re making a plain text editor, you must change the document type settings.&lt;/p&gt;&#xA;&lt;h4 id=&#34;documenttypes&#34;&gt;Document Types&lt;/h4&gt;&#xA;&lt;p&gt;Every document type in a SwiftUI app requires you to supply the following information:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Name&lt;/li&gt;&#xA;&lt;li&gt;Identifier&lt;/li&gt;&#xA;&lt;li&gt;Handler Rank&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The name describes the document. Enter a descriptive name in the text field.&lt;/p&gt;&#xA;&lt;p&gt;The identifier uniquely identifies the document type. An iOS app has a Types text field to enter the identifier. Apple has a &lt;a href=&#34;https://developer.apple.com/documentation/uniformtypeidentifiers/system_declared_uniform_type_identifiers/&#34;&gt;list of system defined types&lt;/a&gt; for common file types. But you can also define your own type using the following convention:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;com.CompanyName.DocumentName&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I found in an app I’m developing that the document had the wrong file extension and type on the Mac until I made the &lt;code&gt;DocumentName&lt;/code&gt; part of the identifier match the file extension for the document. I didn’t have this problem on iOS.&lt;/p&gt;&#xA;&lt;p&gt;The handler rank tells Xcode whether your app owns the document type. In most cases you can choose Default.&lt;/p&gt;&#xA;&lt;p&gt;Mac document types also require you to choose whether your app can edit documents of that type or just view them. Choose Editor to let people edit documents in your app.&lt;/p&gt;&#xA;&lt;h4 id=&#34;exportedtypeidentifiers&#34;&gt;Exported Type Identifiers&lt;/h4&gt;&#xA;&lt;p&gt;You need an exported type identifier for each document type your app owns. If you create a custom document type for your app, you must add an exported type identifier for the custom document type. Do not add exported type identifiers for file types your app exports.&lt;/p&gt;&#xA;&lt;p&gt;You must supply the following information for an exported type identifier:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Description&lt;/li&gt;&#xA;&lt;li&gt;File extension&lt;/li&gt;&#xA;&lt;li&gt;Identifier&lt;/li&gt;&#xA;&lt;li&gt;Conforming identifiers&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you are adding a description for a custom document type, the description usually matches the name of the document type.&lt;/p&gt;&#xA;&lt;p&gt;Enter the file extension without the leading dot in the Extensions text field.&lt;/p&gt;&#xA;&lt;p&gt;The identifier should match the identifier for the document type.&lt;/p&gt;&#xA;&lt;p&gt;You may be able to avoid entering conforming identifiers, but most document types require them. The conforming identifiers are a list of identifiers the type identifier conforms to. For example if you have a custom document type that saves the document in a file package, it must conform to &lt;code&gt;com.apple.package&lt;/code&gt;. If you look at the &lt;a href=&#34;https://developer.apple.com/documentation/uniformtypeidentifiers/system_declared_uniform_type_identifiers/&#34;&gt;list of system defined types&lt;/a&gt;, the Apple System Base Types section has the most common conforming types.&lt;/p&gt;&#xA;&lt;p&gt;There are also fields to enter a MIME type and a reference URL for the exported type identifier. If your document type has a MIME type or a reference URL, enter them in the appropriate fields.&lt;/p&gt;&#xA;&lt;h4 id=&#34;importedtypeidentifiers&#34;&gt;Imported Type Identifiers&lt;/h4&gt;&#xA;&lt;p&gt;Imported type identifiers are for types your app uses but doesn’t own. Xcode provides an imported type identifier for your document type. If your app imports other file types, you must add imported type identifiers for the other types. If you’re making an image editor, you would add imported type identifiers for the image file formats your app supports, such as PNG and JPEG files.&lt;/p&gt;&#xA;&lt;p&gt;You supply the same information for imported type identifiers as you do for exported type identifiers so I’m not going to repeat the information here.&lt;/p&gt;&#xA;&lt;h3 id=&#34;swiftuicodefordocumenttypes&#34;&gt;SwiftUI Code for Document Types&lt;/h3&gt;&#xA;&lt;p&gt;Open the Swift file for the document struct and you should see the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;UTType&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; exampleText: UTType {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    UTType(importedAs: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;com.example.plain-text&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; readableContentTypes: [UTType] { [.exampleText] }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you changed the document type, you should replace the string &lt;code&gt;com.example.plain-text&lt;/code&gt; with the identifier for your app’s document type. You should also change the variable name &lt;code&gt;exampleText&lt;/code&gt; to something that better describes your document type.&lt;/p&gt;&#xA;&lt;p&gt;Notice that the init for &lt;code&gt;UTType&lt;/code&gt; has an &lt;code&gt;importedAs&lt;/code&gt; argument. The &lt;code&gt;UTType&lt;/code&gt; class reference in Apple’s documentation has a list of inits you can use for your document types.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;readableContentTypes&lt;/code&gt; property contains an array of the document types your app can read. There should be an array entry for each imported type identifier in your app. Apple has Swift enums for common document types.&lt;/p&gt;&#xA;&lt;p&gt;SwiftUI documents also have a &lt;code&gt;writableContentTypes&lt;/code&gt; property. This property defaults to matching the readable content types. If your app exports to a type that is not in &lt;code&gt;readableContentTypes&lt;/code&gt;, you must add a variable for the writable content types and supply the writable types.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Replace PDF with the file types your app&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// can export and save.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; writableContentTypes: [UTType] { [.pdf] }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;&#xA;&lt;p&gt;The most important points about SwiftUI document types are the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Document types must have a unique identifier.&lt;/li&gt;&#xA;&lt;li&gt;Add exported type identifiers for any custom document types you make.&lt;/li&gt;&#xA;&lt;li&gt;Add imported type identifiers for any file types your app can import.&lt;/li&gt;&#xA;&lt;li&gt;You need a &lt;code&gt;UTType&lt;/code&gt; property in your code for the document type.&lt;/li&gt;&#xA;&lt;li&gt;You need to supply a &lt;code&gt;readableContentTypes&lt;/code&gt; array in your code with an entry for each imported type identifier.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I have a &lt;a href=&#34;https://github.com/SwiftDevJournal/WikiDemo&#34;&gt;WikiDemo project on GitHub&lt;/a&gt; that has its own document type. Clone the project to examine the settings for the document type, exported type identifiers, and imported type identifiers.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Edit Swift Files Outside Xcode</title>
      <link>https://swiftdevjournal.com/edit-swift-files-outside-xcode-2/</link>
      <pubDate>Wed, 24 Nov 2021 19:21:36 +0000</pubDate>
      <guid>https://swiftdevjournal.com/edit-swift-files-outside-xcode-2/</guid>
      <description>&lt;p&gt;Does Xcode’s editor frustrate you? Do you have problems with Xcode’s code completion? Do you wish you could use a different text editor to edit the Swift files in your Xcode projects?&lt;/p&gt;&#xA;&lt;p&gt;Xcode supports opening and editing Swift files in other text editors, such as BBEdit, Sublime Text, TextMate, and Visual Studio Code. Keep reading to learn how to use your favorite text editor to edit the Swift files in your Xcode projects.&lt;/p&gt;&#xA;&lt;h3 id=&#34;makeyourtexteditorthedefaulteditorforswiftfiles&#34;&gt;Make Your Text Editor the Default Editor for Swift Files&lt;/h3&gt;&#xA;&lt;p&gt;Start by making your preferred text editor the default editor for Swift files on your Mac. Perform the following steps to change the default editor for Swift files:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Go to the Finder.&lt;/li&gt;&#xA;&lt;li&gt;Select a Swift file.&lt;/li&gt;&#xA;&lt;li&gt;Press Cmd-I to open the file’s info panel.&lt;/li&gt;&#xA;&lt;li&gt;Choose your text editor from the Open with menu.&lt;/li&gt;&#xA;&lt;li&gt;Click the Change All button.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/OpenWithTextEditorPanel-2.png&#34; alt=&#34;open with text editor panel&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Now when you open a Swift file in the Finder, the file opens in your text editor.&lt;/p&gt;&#xA;&lt;h3 id=&#34;openingfromxcode&#34;&gt;Opening from Xcode&lt;/h3&gt;&#xA;&lt;p&gt;The final step is to open the Swift files in your text editor from Xcode. Select a Swift file in Xcode’s project navigator, right-click, and choose Open with External Editor. The file will open in your text editor.&lt;/p&gt;&#xA;&lt;p&gt;The changes you make to the text in your text editor will also appear in Xcode. If your project is under version control, an M will appear next to the file in the project navigator, indicating you modified the file.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Disable a Text Field in a SwiftUI List Until Tapping Edit Button</title>
      <link>https://swiftdevjournal.com/disable-a-text-field-in-a-swiftui-list-until-tapping-edit-button/</link>
      <pubDate>Tue, 02 Nov 2021 18:03:09 +0000</pubDate>
      <guid>https://swiftdevjournal.com/disable-a-text-field-in-a-swiftui-list-until-tapping-edit-button/</guid>
      <description>&lt;p&gt;SwiftUI lists support using text fields to change the name of list items. But if your list items are navigation links, you will run into some annoying behavior on iOS. You tap a list item expecting to go to the navigation link destination, but you end up changing the name of the list item.&lt;/p&gt;&#xA;&lt;p&gt;When you tap a list item that is a navigation link, you normally want to go to the link destination. But you still want to be able to rename list items. In SwiftUI iOS apps, you can disable the list item’s text field until someone taps the Edit button. In edit mode you can tap the list item to rename it. When the person taps the Done button, disable the text field.&lt;/p&gt;&#xA;&lt;h3 id=&#34;variablestoaddtotheswiftuiview&#34;&gt;Variables to Add to the SwiftUI View&lt;/h3&gt;&#xA;&lt;p&gt;Start by adding two variables to your SwiftUI view that has the list. The first variable is an environment variable for the editing mode. This variable tracks when someone taps the Edit and Done buttons.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Environment(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.editMode) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; editMode&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second variable is a Boolean value that tracks if the text field is disabled. The name &lt;code&gt;disabled&lt;/code&gt; is used by SwiftUI. I got a compiler error when I named the variable &lt;code&gt;disabled&lt;/code&gt; so use another name for the variable.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; disableTextField = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The text field should be disabled until someone taps the Edit button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;modifierstoaddtothetextfield&#34;&gt;Modifiers to Add to the Text Field&lt;/h3&gt;&#xA;&lt;p&gt;Add two modifiers to the text field. The first modifier is the &lt;code&gt;.disabled&lt;/code&gt; modifier. Supply the Boolean variable you added to the view.&lt;/p&gt;&#xA;&lt;p&gt;The second modifier is the &lt;code&gt;.onChange&lt;/code&gt; modifier. The change you’re going to track is the change in edit mode. When someone taps the Edit button, the &lt;code&gt;isEditing&lt;/code&gt; property is set to true. Set the Boolean variable to false, which enables editing in the text field. When someone taps the Done button, &lt;code&gt;isEditing&lt;/code&gt; becomes false. Set the Boolean variable to true, which disables editing in the text field.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TextField(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, text: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;item.name)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .disabled(disableTextField)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .onChange(of: editMode?.wrappedValue) { newValue &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (newValue &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (newValue!.isEditing) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Edit button tapped&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      disableTextField = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Done button tapped&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      disableTextField = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sampleproject&#34;&gt;Sample Project&lt;/h3&gt;&#xA;&lt;p&gt;I have a &lt;a href=&#34;https://github.com/SwiftDevJournal/WikiDemo&#34;&gt;sample project on GitHub&lt;/a&gt;. Look at the &lt;code&gt;PageListView.swift&lt;/code&gt; file in the iOS folder to see the code for disabling the text fields in the list.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Moving List Items Using Drag and Drop in SwiftUI Mac Apps</title>
      <link>https://swiftdevjournal.com/moving-list-items-using-drag-and-drop-in-swiftui-mac-apps/</link>
      <pubDate>Thu, 28 Oct 2021 18:44:05 +0000</pubDate>
      <guid>https://swiftdevjournal.com/moving-list-items-using-drag-and-drop-in-swiftui-mac-apps/</guid>
      <description>&lt;p&gt;Mac apps usually use drag and drop to rearrange items in a list. You search for how to move list items in SwiftUI, and you find a bunch of examples for iOS that use the &lt;code&gt;.onMove&lt;/code&gt; modifier. But when you start to type &lt;code&gt;.onMove&lt;/code&gt; in your Mac list, Xcode’s autocomplete shows only an &lt;code&gt;.onMoveCommand&lt;/code&gt; modifier. If you try to use &lt;code&gt;.onMove&lt;/code&gt; directly on a list in a Mac app, you’ll get a compiler error.&lt;/p&gt;&#xA;&lt;p&gt;SwiftUI has an &lt;code&gt;.onMoveCommand&lt;/code&gt; modifier to move items in a list in a SwiftUI Mac app, but it works with the keyboard, not with drag and drop. How do you use drag and drop to move items in a SwiftUI list in a Mac app?&lt;/p&gt;&#xA;&lt;h3 id=&#34;.onmoverequiresforeachonmac&#34;&gt;.onMove Requires ForEach on Mac&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;code&gt;.onMove&lt;/code&gt; modifier is the modifier to use to move list items using drag and drop in SwiftUI Mac apps. But you must place a &lt;code&gt;ForEach&lt;/code&gt; statement inside the list to enable &lt;code&gt;.onMove&lt;/code&gt;. The &lt;code&gt;ForEach&lt;/code&gt; statement takes two arguments: the array of items you’re showing in the list and an ID that uniquely identifies each list item.&lt;/p&gt;&#xA;&lt;p&gt;Apply the &lt;code&gt;.onMove&lt;/code&gt; modifier to the &lt;code&gt;ForEach&lt;/code&gt; block. The &lt;code&gt;.onMove&lt;/code&gt; modifier’s closure takes two arguments: the indices for the list items being moved and the drop destination. Call the array’s &lt;code&gt;move&lt;/code&gt; method to reorder the list items.&lt;/p&gt;&#xA;&lt;p&gt;The following code creates a list of a book’s chapters that you can rearrange using drag and drop:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// The chapter has an id property that uniquely identifies it.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ForEach(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;book.chapters, id: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.id) { &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;chapter &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TextField(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, text: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;chapter.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .onMove { indices, destination &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    book.chapters.move(fromOffsets: indices, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      toOffset: destination)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>What Xcode Files Should Git Track and Ignore?</title>
      <link>https://swiftdevjournal.com/what-xcode-files-should-git-track-and-ignore/</link>
      <pubDate>Thu, 21 Oct 2021 19:08:30 +0000</pubDate>
      <guid>https://swiftdevjournal.com/what-xcode-files-should-git-track-and-ignore/</guid>
      <description>&lt;p&gt;When you start using version control in your Xcode projects, you may become confused about which files git should track and which files git should ignore. This confusion is normal. Xcode projects contain much more than your Swift files, and some of these extra files are basically unreadable. What files in your project should you tell git to ignore?&lt;/p&gt;&#xA;&lt;p&gt;Fortunately the site &lt;a href=&#34;https://www.toptal.com/developers/gitignore&#34;&gt;gitignore.io&lt;/a&gt; has solved this problem for you. Go to gitignore.io, enter &lt;strong&gt;Xcode&lt;/strong&gt; in the search field, and click the Create button. You will get a git ignore file with a list of file types that git should ignore. Add the git ignore file to your project folder.&lt;/p&gt;&#xA;&lt;h3 id=&#34;needmoreinformationonusinggitwithxcode&#34;&gt;Need More Information on Using Git with Xcode?&lt;/h3&gt;&#xA;&lt;p&gt;Check out &lt;a href=&#34;https://www.swiftdevjournal.com/version-control-book/&#34;&gt;my version control book&lt;/a&gt;. It has an entire chapter on ignoring files, including what to do when git starts tracking an unwanted file.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Accessing the Document in a SwiftUI Menu</title>
      <link>https://swiftdevjournal.com/accessing-the-document-in-a-swiftui-menu/</link>
      <pubDate>Mon, 20 Sep 2021 17:50:02 +0000</pubDate>
      <guid>https://swiftdevjournal.com/accessing-the-document-in-a-swiftui-menu/</guid>
      <description>&lt;p&gt;You’re making a SwiftUI document-based Mac app. You have a menu item in your app that performs an action on the document. How do you give the menu access to the document?&lt;/p&gt;&#xA;&lt;p&gt;Use focused values and focused bindings.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingafocusedvalue&#34;&gt;Creating a Focused Value&lt;/h3&gt;&#xA;&lt;p&gt;A focused value provides a way for a SwiftUI app to observe values from the focused view or one of its ancestors. In a document-based SwiftUI Mac app, one of the focused view’s ancestors is the document window. By using a focused value your app can access the focused document.&lt;/p&gt;&#xA;&lt;p&gt;To create a focused value, you must write two pieces of code. The first is a struct that conforms to the &lt;code&gt;FocusedValueKey&lt;/code&gt; protocol. The second is a property for the document as an extension to the &lt;code&gt;FocusedValues&lt;/code&gt; struct.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DocumentFocusedValueKey&lt;/span&gt;: FocusedValueKey {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;typealias&lt;/span&gt; Value = Binding&amp;lt;Document&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FocusedValues&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: DocumentFocusedValueKey.Value? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;[DocumentFocusedValueKey.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;[DocumentFocusedValueKey.&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;] = newValue&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The struct creates a type alias for the document’s type, which is usually a binding to your document type.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;document&lt;/code&gt; variable is the value you will use when setting the focused value. The value must match this variable name.&lt;/p&gt;&#xA;&lt;p&gt;Notice the type of the variable, &lt;code&gt;DocumentFocusedValueKey.Value?&lt;/code&gt;. The first part of the type is the name of the struct you created for the focused value. The second part is the name of the type alias you created in the struct.&lt;/p&gt;&#xA;&lt;h3 id=&#34;settingafocusedvalue&#34;&gt;Setting a Focused Value&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;code&gt;.focusedValue&lt;/code&gt; modifier sets a focused value.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.focusedValue(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.document, value)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The name of the first argument must match the name of the variable you created in the &lt;code&gt;FocusedValues&lt;/code&gt; extension.&lt;/p&gt;&#xA;&lt;p&gt;Apple added the &lt;code&gt;.focusedSceneValue&lt;/code&gt; modifier in iOS 15 and macOS 12. This modifier works much better than &lt;code&gt;.focusedValue&lt;/code&gt;, which requires the person using the app to be focused on a text view or text field. If you can require iOS 15 and/or macOS 12, use &lt;code&gt;.focusedSceneValue&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.focusedSceneValue(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.document, value)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where do you place the code to set the focused value? Attaching the focused value modifier to the content view in the app file is the most common place in a document-based SwiftUI app.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Scene {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  DocumentGroup(newDocument: Document()) { file &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// The document argument matches the name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// of a property in the content view, &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// giving the content view access to the document.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ContentView(document: file.&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Give the app access to the document.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      .focusedSceneValue(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.document, file.&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;focusedbindings&#34;&gt;Focused Bindings&lt;/h3&gt;&#xA;&lt;p&gt;A focused binding gives a SwiftUI view access to the focused value. To create a focused binding, declare a variable with the &lt;code&gt;@FocusedBinding&lt;/code&gt; property wrapper and supply the name of the focused value in parentheses.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@FocusedBinding(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.document) &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: Document?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;usingfocusedbindingsinswiftuimenus&#34;&gt;Using Focused Bindings in SwiftUI Menus&lt;/h4&gt;&#xA;&lt;p&gt;To use a focused binding in a SwiftUI menu, you must create a SwiftUI view for the menu items. Create the menu items in the group. The following example shows a menu with items to make text bold and italic:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BoldItalicView&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @FocusedBinding(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.document) &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: Document?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Group {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// In your app call a function that&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// does something to the document.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        applyMarkup(tagType: .bold, document: document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Bold&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }).keyboardShortcut(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;, modifiers: [.command])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;Button(action: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;applyMarkup(tagType: .italic, document: document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;}, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Italic&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;}).keyboardShortcut(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;i&amp;#34;&lt;/span&gt;, modifiers: [.command])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;creatingmenucommands&#34;&gt;Creating Menu Commands&lt;/h4&gt;&#xA;&lt;p&gt;If you have a menu with multiple menu items, creating a set of menu commands lets you keep the menu creation code in its own Swift file. To create a set of menu commands, supply the views inside the &lt;code&gt;CommandMenu&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MarkupCommands&lt;/span&gt;: Commands {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Commands {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CommandMenu(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Markup&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;BoldItalicView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Add other menu items here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;addthemenutotheapp&#34;&gt;Add the Menu to the App&lt;/h3&gt;&#xA;&lt;p&gt;The final step is to add the menu to the app.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Swift_Book_BuilderApp&lt;/span&gt;: App {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Scene {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DocumentGroup(newDocument: Document()) { file &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ContentView(document: file.&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .focusedValue(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.document, file.&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .commands {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      MarkupCommands()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By creating a struct for the menu commands, the code inside the app’s body is much cleaner.&lt;/p&gt;&#xA;&lt;h3 id=&#34;credits&#34;&gt;Credits&lt;/h3&gt;&#xA;&lt;p&gt;I learned much of the information shared in this article from the following article by Lost Moa:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://nilcoalescing.com/blog/ProvidingTheCurrentDocumentToMenuCommands&#34;&gt;Provide the current document to menu commands in a SwiftUI app&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Using New API Features in Swift While Supporting Older OS Versions</title>
      <link>https://swiftdevjournal.com/using-new-api-features-in-swift-while-supporting-older-os-versions/</link>
      <pubDate>Wed, 08 Sep 2021 18:07:59 +0000</pubDate>
      <guid>https://swiftdevjournal.com/using-new-api-features-in-swift-while-supporting-older-os-versions/</guid>
      <description>&lt;p&gt;Every year at WWDC Apple adds new features to their developer SDKs. Usually these new features require the upcoming version of iOS and macOS. You would like to use the new features while also supporting older versions of iOS and macOS. How do you do this?&lt;/p&gt;&#xA;&lt;p&gt;Apple provides two Swift keywords to use both new code and old code in your apps: &lt;code&gt;#available&lt;/code&gt; and &lt;code&gt;@available&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;available&#34;&gt;#available&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;code&gt;#available&lt;/code&gt; keyword works with &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;guard&lt;/code&gt; statements. Supply an operating system version version, and the code inside the &lt;code&gt;if&lt;/code&gt; block (or after the &lt;code&gt;guard&lt;/code&gt;) executes only on machines capable of running the code. Use the &lt;code&gt;else&lt;/code&gt; block for code to run on older operating systems. The following example shows how to run one block of code on iOS 15 and another block on earlier iOS versions:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#available&lt;/span&gt;(&lt;span style=&#34;color:#75715e&#34;&gt;iOS&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// iOS 15 code here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Code for earlier iOS versions&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following example shows how to run one block of code on macOS 12 and another block on earlier macOS versions:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#available&lt;/span&gt;(&lt;span style=&#34;color:#75715e&#34;&gt;macOS&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// macOS 12 code here            &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// code for earlier Mac versions&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;whatdoestheasteriskdo&#34;&gt;What Does the Asterisk Do?&lt;/h4&gt;&#xA;&lt;p&gt;The asterisk in the last argument to &lt;code&gt;#available&lt;/code&gt; tells the compiler to require the minimum deployment target for other platforms. You must always supply the asterisk to support future platforms Apple may add.&lt;/p&gt;&#xA;&lt;h4 id=&#34;checkingformultipleplatforms&#34;&gt;Checking for Multiple Platforms&lt;/h4&gt;&#xA;&lt;p&gt;Suppose you have a multiplatform SwiftUI project and you want to conditionally run code for iOS 15 and macOS 12. Supply the second platform operating system as an additional argument to &lt;code&gt;#available&lt;/code&gt;. The following example checks for both iOS 15 and macOS 12:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#available&lt;/span&gt;(&lt;span style=&#34;color:#75715e&#34;&gt;iOS&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#75715e&#34;&gt;macOS&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Code for newer systems here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Code for older systems here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;guardstatements&#34;&gt;guard Statements&lt;/h4&gt;&#xA;&lt;p&gt;Using &lt;code&gt;available&lt;/code&gt; with a &lt;code&gt;guard&lt;/code&gt; statement works best with code that should only run on newer versions of iOS and macOS. You can exit and do nothing on machines running on older operating systems.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#available&lt;/span&gt;(&lt;span style=&#34;color:#75715e&#34;&gt;iOS&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// iOS 15 code here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;available&#34;&gt;@available&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;code&gt;@available&lt;/code&gt; keyword lets you mark a function, struct, or class as being available only on certain versions of iOS and macOS. Supply the same information as &lt;code&gt;#available&lt;/code&gt;: an operating system version and an asterisk. The following code demonstrates the use of &lt;code&gt;@available&lt;/code&gt; in a function:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@available(iOS &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;myiOS15Function&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Struct example:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@available(macOS &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyMacOS12Struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Class example with multiple platforms:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@available(iOS &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, macOS &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyMultiplatformClass&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Convert a Swift Range to Use String.Index</title>
      <link>https://swiftdevjournal.com/convert-a-swift-range-to-use-string-index/</link>
      <pubDate>Thu, 02 Sep 2021 18:44:53 +0000</pubDate>
      <guid>https://swiftdevjournal.com/convert-a-swift-range-to-use-string-index/</guid>
      <description>&lt;h3 id=&#34;thesituation&#34;&gt;The Situation&lt;/h3&gt;&#xA;&lt;p&gt;I was working on a SwiftUI app where I wanted to select text in a text view and insert some text at the start of the selection. SwiftUI’s native text editor currently does not support getting the selection range so I had to wrap an AppKit text view and store the selection range when the selection changes.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;textViewDidChangeSelection&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; notification: Notification) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; textView = notification.object &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    NSTextView &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  control.model.selectionRange = &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Range.&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(textView.selectedRange())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;theproblem&#34;&gt;The Problem&lt;/h3&gt;&#xA;&lt;p&gt;The code in the previous example gives me a Swift range, which uses integers, &lt;code&gt;Range&amp;lt;Int&amp;gt;&lt;/code&gt;. I wanted to use the selection range’s start index as the destination to insert the string.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;model.text.insert(contentsOf: textToInsert, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  at: model.selectionRange?.startIndex)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But the compiler gave me an error. The reason for the error is the &lt;code&gt;String&lt;/code&gt; struct’s &lt;code&gt;insert&lt;/code&gt; method takes a range that uses string indexes, &lt;code&gt;Range&amp;lt;String.Index&amp;gt;&lt;/code&gt;, not integers.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thesolution&#34;&gt;The Solution&lt;/h3&gt;&#xA;&lt;p&gt;The solution is to create a string index for the string and use that as the argument to the &lt;code&gt;insert&lt;/code&gt; method. The base for the string index is the string’s start index. The offset for the string index is the selection range’s lower bound.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; insertionPoint = model.text.index(model.text.startIndex, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  offsetBy: model.selectionRange?.lowerBound ?? &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;model.text.insert(contentsOf: textToInsert, at: insertionPoint)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Using File Wrappers in a SwiftUI App</title>
      <link>https://swiftdevjournal.com/using-file-wrappers-in-a-swiftui-app/</link>
      <pubDate>Fri, 27 Aug 2021 18:11:55 +0000</pubDate>
      <guid>https://swiftdevjournal.com/using-file-wrappers-in-a-swiftui-app/</guid>
      <description>&lt;h3 id=&#34;whatisafilewrapper&#34;&gt;What Is a File Wrapper?&lt;/h3&gt;&#xA;&lt;p&gt;A file wrapper is a bundle, which is a collection of one or more directories (folders) and files that appears as a single file in the Finder (Mac) or Files app (iOS). Most Mac applications use bundles. If you want to see what a bundle looks like, select an application, right-click, and choose Show Package Contents.&lt;/p&gt;&#xA;&lt;p&gt;When should you use a file wrapper? Use a file wrapper when you want to save your app’s data in multiple files. Suppose you’re developing a website building app. A website can have multiple pages, plus folders and files for images, videos, and custom CSS. By using a file wrapper you can save all these files and have it look like a single file to the person using the app. Most apps don’t need to use file wrappers&lt;/p&gt;&#xA;&lt;h3 id=&#34;typesoffilewrappers&#34;&gt;Types of File Wrappers&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;code&gt;FileWrapper&lt;/code&gt; class has the following file wrappers:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Directory&lt;/li&gt;&#xA;&lt;li&gt;Regular file&lt;/li&gt;&#xA;&lt;li&gt;Symbolic link&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The symbolic link file wrapper points to a file. The most common case of using a symbolic link file wrapper is to point to a large file (image, audio, or video file) to keep the wrapper from getting too big. I’m going to focus on directory and regular file wrappers in this article.&lt;/p&gt;&#xA;&lt;h3 id=&#34;makingyourfilewrapperappearasasinglefile&#34;&gt;Making Your File Wrapper Appear as a Single File&lt;/h3&gt;&#xA;&lt;p&gt;Document-based apps are more likely to use file wrappers than shoebox apps. If you forget to configure the document to be a file wrapper, the document will appear as a folder instead of a single file.&lt;/p&gt;&#xA;&lt;p&gt;To configure the document to be a file wrapper, perform the following steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Select the project from the project navigator to open the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Select the app from the Targets list in the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Click the Info button at the top of the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Click the disclosure triangle next to the Exported Type Identifiers section in the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Enter &lt;code&gt;com.apple.package&lt;/code&gt; in the Conforms To text field.&lt;/li&gt;&#xA;&lt;li&gt;Click the disclosure triangle next to the Imported Type Identifiers section in the project editor.&lt;/li&gt;&#xA;&lt;li&gt;Enter &lt;code&gt;com.apple.package&lt;/code&gt; in the Conforms To text field.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;creatingadocumentfilewrapper&#34;&gt;Creating a Document File Wrapper&lt;/h3&gt;&#xA;&lt;p&gt;You must create a file wrapper when saving the document. If you create a document-based SwiftUI app, you should see the following function in the document struct’s Swift file:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fileWrapper&lt;/span&gt;(configuration: WriteConfiguration) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; FileWrapper&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function is called when saving the document. Your code to create the file wrapper goes in this function.&lt;/p&gt;&#xA;&lt;p&gt;To create a file wrapper you must perform the following tasks:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a directory file wrapper&lt;/li&gt;&#xA;&lt;li&gt;Convert your app’s data to a &lt;code&gt;Data&lt;/code&gt; object&lt;/li&gt;&#xA;&lt;li&gt;Create a regular file wrapper&lt;/li&gt;&#xA;&lt;li&gt;Add the file to a directory file wrapper&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;creatingadirectoryfilewrapper&#34;&gt;Creating a Directory File Wrapper&lt;/h4&gt;&#xA;&lt;p&gt;At a minimum you must create a root directory for the file wrapper. You will return this wrapper in the call to &lt;code&gt;fileWrapper&lt;/code&gt;. To create a directory file wrapper, call the &lt;code&gt;FileWrapper&lt;/code&gt; method &lt;code&gt;directoryWithFileWrappers&lt;/code&gt; and supply an empty Swift dictionary.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; mainDirectory = FileWrapper(directoryWithFileWrappers: [:])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Call &lt;code&gt;directoryWithFileWrappers&lt;/code&gt; and supply an empty dictionary for any additional directories you want to create.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; pagesDirectory = FileWrapper(directoryWithFileWrappers: [:])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The root directory of a wrapper does not need a name because it does not appear in the Finder or Files app. But any other directories you create require a name. Set the &lt;code&gt;preferredFilename&lt;/code&gt; property to name the directory.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pagesDirectory.preferredFilename = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Pages&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Call the &lt;code&gt;addFileWrapper&lt;/code&gt; method to add the directory to the root directory.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mainDirectory.addFileWrapper(pagesDirectory)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;convertappdatatoadataobject&#34;&gt;Convert App Data to a Data Object&lt;/h4&gt;&#xA;&lt;p&gt;Files in file wrappers store their data in a &lt;code&gt;Data&lt;/code&gt; object. You must convert your app’s data to &lt;code&gt;Data&lt;/code&gt; to use file wrappers. Converting to &lt;code&gt;Data&lt;/code&gt; depends on what you are storing, but the following code converts a string to &lt;code&gt;Data&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; pageData = pageString.data(using: .utf8)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;creatingaregularfilewrapper&#34;&gt;Creating a Regular File Wrapper&lt;/h4&gt;&#xA;&lt;p&gt;To create a file wrapper for a regular file, call the &lt;code&gt;FileWrapper&lt;/code&gt; method &lt;code&gt;regularFileWithContents&lt;/code&gt; and supply the &lt;code&gt;Data&lt;/code&gt; object that contains the file’s data.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; wrapper = FileWrapper(regularFileWithContents: data)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set the &lt;code&gt;preferredFilename&lt;/code&gt; property to name the file.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wrapper.preferredFilename = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;index.html&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In a real app you won’t be hardcoding filenames often. Suppose you have a document that has a list of pages. You would use the page’s title as the filename instead of giving the file a specific name. Remember that you use file wrappers to save multiple files. If you have 20 files to save, hardcoding the name of each file is going to be a pain. The following code demonstrates how to save a collection of text files:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// A page has a title and text&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; page &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; pages {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; data = page.write() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; wrapper = FileWrapper(regularFileWithContents: data)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    wrapper.preferredFilename = page.title&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pagesDirectory.addFileWrapper(wrapper)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;() -&amp;gt; Data? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; text.data(using: .utf8)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Call &lt;code&gt;addFileWrapper&lt;/code&gt; to add a file to a directory.&lt;/p&gt;&#xA;&lt;h3 id=&#34;readingfromafilewrapper&#34;&gt;Reading from a File Wrapper&lt;/h3&gt;&#xA;&lt;p&gt;At this point you know how to create a file wrapper and save data to it. The next step is to read data from the file wrapper when opening a document.&lt;/p&gt;&#xA;&lt;p&gt;The SwiftUI document structure provides the following initializer to read data from a file wrapper:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(configuration: ReadConfiguration) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This initializer is where you add the code to read from the file wrapper. To read from a file wrapper, you must perform the following tasks:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Access the directory holding the files&lt;/li&gt;&#xA;&lt;li&gt;Read the individual files&lt;/li&gt;&#xA;&lt;li&gt;Load the data from the file&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;accessthedirectoryholdingthefiles&#34;&gt;Access the Directory Holding the Files&lt;/h4&gt;&#xA;&lt;p&gt;If you store all the files inside the root directory, you won’t need to write any code to access the directory. But if you have files inside a subdirectory, you must call the &lt;code&gt;fileWrappers&lt;/code&gt; method and supply the name of the subdirectory as the dictionary value.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; wrappers = mainDirectory.fileWrappers {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; pagesDirectory = wrappers[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Pages&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The SwiftUI initializer takes a read configuration as an argument. The &lt;code&gt;ReadConfiguration&lt;/code&gt; struct has a &lt;code&gt;file&lt;/code&gt; property that provides access to the root directory of the file wrapper.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(configuration: ReadConfiguration) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; pagesDirectory = configuration.file.fileWrappers?[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Pages&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; CocoaError(.fileReadCorruptFile)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;readingtheindividualfiles&#34;&gt;Reading the Individual Files&lt;/h4&gt;&#xA;&lt;p&gt;Use the &lt;code&gt;fileWrappers&lt;/code&gt; property to access the files in a directory file wrapper. Go through each file and load the data. Use the &lt;code&gt;regularFileContents&lt;/code&gt; property to access the file contents.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; pageFiles = pagesDirectory.fileWrappers {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; pageFile &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; pageFiles {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    readPage(pageFile: pageFile.value)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;mutating&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;readPage&lt;/span&gt;(pageFile: FileWrapper) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; filename = pageFile.filename,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fileData = pageFile.regularFileContents {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Create a page, load the data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// from the file, and add it to an array.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; page = Page()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    page.title = filename&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    page.read(data: fileData)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pages.append(page)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;loadingthedata&#34;&gt;Loading the Data&lt;/h4&gt;&#xA;&lt;p&gt;The file wrapper’s &lt;code&gt;regularFileContents&lt;/code&gt; property gives you a &lt;code&gt;Data&lt;/code&gt; object to load the file’s contents in your app. Loading the file’s contents depends on the type of data being stored. The following code loads a file’s contents into a string variable:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(data: Data) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fileContents = String(data: data, encoding: .utf8) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    text = fileContents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sampleproject&#34;&gt;Sample Project&lt;/h3&gt;&#xA;&lt;p&gt;I have &lt;a href=&#34;https://github.com/SwiftDevJournal/WikiDemo&#34;&gt;a sample project on GitHub&lt;/a&gt; that demonstrates saving data to a file wrapper. Look at the files &lt;code&gt;Wiki.swift&lt;/code&gt; and &lt;code&gt;Page.swift&lt;/code&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Creating a Master-Detail Interface in SwiftUI</title>
      <link>https://swiftdevjournal.com/creating-a-master-detail-inteface-in-swiftui/</link>
      <pubDate>Mon, 23 Aug 2021 18:27:46 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-a-master-detail-inteface-in-swiftui/</guid>
      <description>&lt;p&gt;Master-detail interfaces are common in iOS and Mac apps. Select an item from the master view to see additional information in the detail view. In SwiftUI you use two views to create a master-detail interface: &lt;code&gt;NavigationView&lt;/code&gt; and &lt;code&gt;NavigationLink&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Apple deprecated &lt;code&gt;NavigationView&lt;/code&gt; in iOS 16 and macOS 13. The replacements for &lt;code&gt;NavigationView&lt;/code&gt; are &lt;code&gt;NavigationStack&lt;/code&gt; and &lt;code&gt;NavigationSplitView&lt;/code&gt;, but they require iOS 16+ and macOS 13+. If you want to support earlier OS versions, you must use &lt;code&gt;NavigationView&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;navigationview&#34;&gt;Navigation View&lt;/h3&gt;&#xA;&lt;p&gt;A navigation view is the most common way to create a master-detail interface in SwiftUI. On iOS selecting an item from the master view, which is usually a SwiftUI list, takes you to the detail view. On macOS selecting an item from the master view shows the details in the detail view.&lt;/p&gt;&#xA;&lt;p&gt;The following code shows how to create a navigation view:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  NavigationView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    MasterView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DetailView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In a real app you will pass data as arguments to the master view and detail view. The data depends on your app, which is why I didn’t supply any arguments in the code listing.&lt;/p&gt;&#xA;&lt;p&gt;The article &lt;a href=&#34;https://www.swiftdevjournal.com/passing-data-to-swiftui-views/&#34;&gt;Passing Data to SwiftUI Views&lt;/a&gt; provides more detailed information on passing data to views.&lt;/p&gt;&#xA;&lt;h3 id=&#34;navigationlink&#34;&gt;Navigation Link&lt;/h3&gt;&#xA;&lt;p&gt;The final part of creating a master-detail interface is to add a navigation link in the master view and set its destination to the detail view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List(items) { item &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  NavigationLink(destination: DetailView()) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Text(item.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This example creates a navigation link for each item in the list. Selecting an item from the list fills the detail view with information about the selected item. In a real app you will pass the data to show in the detail view as an argument to the detail view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;handlingselection&#34;&gt;Handling Selection&lt;/h3&gt;&#xA;&lt;p&gt;There are some situations where you may need to hold on to the selection. Mac apps need access to the selected item when deleting an item from a list.&lt;/p&gt;&#xA;&lt;p&gt;In the master view create a property to store the selection. Make it optional and set its value to nil.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; selectedItem: Item? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When someone selects an item from the list, the &lt;code&gt;selectedItem&lt;/code&gt; property will store it. In the call to create the navigation link, add the &lt;code&gt;tag&lt;/code&gt; and &lt;code&gt;selection&lt;/code&gt; arguments. The tag is usually the current item. The selection is the selected item.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List(items) { item &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  NavigationLink(destination: DetailView(),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                tag: item,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &#x9;selection: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;selectedItem) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Text(page.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sampleproject&#34;&gt;Sample Project&lt;/h3&gt;&#xA;&lt;p&gt;I put a &lt;a href=&#34;https://github.com/SwiftDevJournal/WikiDemo&#34;&gt;sample project on master-detail interfaces on GitHub&lt;/a&gt;. It builds upon the project from the &lt;a href=&#34;https://www.swiftdevjournal.com/make-a-markdown-editor-in-swiftui/&#34;&gt;Make a Markdown Editor in SwiftUI&lt;/a&gt; article by displaying a list of Markdown pages to edit. Look at the files &lt;code&gt;ContentView.swift&lt;/code&gt; and &lt;code&gt;PageListView.swift&lt;/code&gt; for the code on making the master-detail interface.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Using a Scrollable Text View in a Mac SwiftUI App</title>
      <link>https://swiftdevjournal.com/using-a-scrollable-text-view-in-a-mac-swiftui-app/</link>
      <pubDate>Mon, 16 Aug 2021 17:40:47 +0000</pubDate>
      <guid>https://swiftdevjournal.com/using-a-scrollable-text-view-in-a-mac-swiftui-app/</guid>
      <description>&lt;p&gt;In the article &lt;a href=&#34;https://www.swiftdevjournal.com/using-text-views-in-a-swiftui-app/&#34;&gt;Using Text Views in a SwiftUI App&lt;/a&gt; I showed how to use a UIKit text view in a SwiftUI app. But if you use the code from that article in a Mac app, you’ll run into a problem. The text view won’t scroll when you reach the bottom of the text view. In this article you’ll learn how to make the text view scroll in a Mac app.&lt;/p&gt;&#xA;&lt;p&gt;Much of the code for this article comes from the &lt;a href=&#34;https://github.com/ZeeZide/CodeEditor&#34;&gt;CodeEditor Swift package&lt;/a&gt;, which is a text editor for SwiftUI with syntax highlighting.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createascrollview&#34;&gt;Create a Scroll View&lt;/h3&gt;&#xA;&lt;p&gt;The reason the text view won’t scroll is that Mac text views aren’t wrapped in scroll views like iOS text views are. When you create the text view, you have to create both a text view and a scroll view. Set the scroll view’s document view to the text view. Give the scroll view a vertical scroller. Return the scroll view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeNSView&lt;/span&gt;(context: Context) -&amp;gt; NSScrollView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; textView = NSTextView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  textView.autoresizingMask = [.width, .height]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  textView.isEditable = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  textView.delegate = context.coordinator&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  textView.allowsUndo = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; scrollView = NSScrollView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scrollView.hasVerticalScroller = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scrollView.documentView = textView&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; scrollView&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Setting the autoresizing mask ensures the text view resizes properly when the window resizes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;updatingtheview&#34;&gt;Updating the View&lt;/h3&gt;&#xA;&lt;p&gt;When writing the &lt;code&gt;updateNSView&lt;/code&gt; function, supply the scroll view as the argument. Use the &lt;code&gt;documentView&lt;/code&gt; property of the scroll view to access the text view and update its contents.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateNSView&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; scrollView: NSScrollView, context: Context) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; textView = scrollView.documentView &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? NSTextView &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    assertionFailure(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unexpected text view&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; textView.delegate &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; context.coordinator {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    textView.delegate = context.coordinator&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// model is your data model whose text you are&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// showing and editing in the text view.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  textView.string = model.text&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Removing Items from SwiftUI Lists in Mac Apps</title>
      <link>https://swiftdevjournal.com/removing-items-from-swiftui-lists-in-mac-apps/</link>
      <pubDate>Thu, 01 Jul 2021 17:35:58 +0000</pubDate>
      <guid>https://swiftdevjournal.com/removing-items-from-swiftui-lists-in-mac-apps/</guid>
      <description>&lt;p&gt;Most examples of removing items from SwiftUI lists use the &lt;code&gt;.onDelete&lt;/code&gt; handler, which is not available for Mac apps. In this article I share what I learned to remove list items from SwiftUI Mac apps.&lt;/p&gt;&#xA;&lt;p&gt;To remove items from SwiftUI lists in Mac apps, you must perform the following tasks:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Add a variable to the list view to store the selected list item.&lt;/li&gt;&#xA;&lt;li&gt;If you are using a navigation link, supply a tag and selection when creating the link.&lt;/li&gt;&#xA;&lt;li&gt;Make your struct or class conform to the &lt;code&gt;Equatable&lt;/code&gt; and &lt;code&gt;Hashable&lt;/code&gt; protocols.&lt;/li&gt;&#xA;&lt;li&gt;Add the &lt;code&gt;.onDeleteCommand&lt;/code&gt; handler to the list. The &lt;code&gt;.onDeleteCommand&lt;/code&gt; handler is the handler SwiftUI Mac apps use to remove list items.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;addaselectionvariabletothelistview&#34;&gt;Add a Selection Variable to the List View&lt;/h3&gt;&#xA;&lt;p&gt;To remove an item from a SwiftUI list, the list view requires a variable to store the item you want to remove. Create an optional for the variable and set it to nil initially.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; selection: ListItemStruct? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ListItemStruct&lt;/code&gt; is the name of the data structure in your app that you want to show in the list.&lt;/p&gt;&#xA;&lt;p&gt;When you supply this selection when creating a navigation link, SwiftUI keeps track of the selected item in the list.&lt;/p&gt;&#xA;&lt;h3 id=&#34;supplyatagandselectiontothenavigationlink&#34;&gt;Supply a Tag and Selection to the Navigation Link&lt;/h3&gt;&#xA;&lt;p&gt;Most SwiftUI apps that use lists use a navigation link to create master-detail interfaces. Select an item from the list to show additional information in the detail view. Add a call to &lt;code&gt;NavigationLink&lt;/code&gt; in the master view and set its destination to the detail view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NavigationLink(destination: DetailView(detailItem: item)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To support more complex selection behavior, you must supply two additional arguments to the navigation link call: &lt;code&gt;tag&lt;/code&gt; and &lt;code&gt;selection&lt;/code&gt;. Usually the tag is the current list item you’re adding to the list. The selection is the variable you added to the list view.&lt;/p&gt;&#xA;&lt;p&gt;The following code demonstrates how to show a list of a book’s chapters:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// The book has an array of chapters.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; book: Book&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; selection: Chapter? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;book.chapters) { &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;chapter &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// ChapterView is a SwiftUI view that &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// displays the chapter&amp;#39;s contents.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  NavigationLink(destination: ChapterView(chapter: chapter), &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tag: chapter, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    selection: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;selection) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TextField(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, text: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;chapter.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This example uses the improved syntax Apple added in Xcode 13 to bind list text fields to items in an array. If you’re using Xcode 12 you will have to use a &lt;code&gt;Text&lt;/code&gt; to display the titles and remove the $ character from &lt;code&gt;$chapter&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;makeyourstructclassconformtoequatableandhashableprotocols&#34;&gt;Make Your Struct/Class Conform to Equatable and Hashable Protocols&lt;/h3&gt;&#xA;&lt;p&gt;To use the &lt;code&gt;tag&lt;/code&gt; and &lt;code&gt;selection&lt;/code&gt; arguments in a navigation link, your struct or class must conform to the &lt;code&gt;Equatable&lt;/code&gt; and &lt;code&gt;Hashable&lt;/code&gt; protocols. Your project won’t compile until you make the struct or class conform to those protocols.&lt;/p&gt;&#xA;&lt;p&gt;Making your struct or class conform to &lt;code&gt;Equatable&lt;/code&gt; requires you to implement the &lt;code&gt;==&lt;/code&gt; operator to check for equality.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; == (lhs: Chapter, rhs: Chapter) -&amp;gt; Bool {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  lhs.id == rhs.id&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace &lt;code&gt;Chapter&lt;/code&gt; with the name of your struct or class. Do whatever comparisons you need to make to determine that two objects are equal. SwiftUI list items require a unique ID. That’s what I used to determine equality in the example.&lt;/p&gt;&#xA;&lt;p&gt;To conform to the &lt;code&gt;Hashable&lt;/code&gt; protocol, you must implement the &lt;code&gt;hash&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hash&lt;/span&gt;(into hasher: &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; Hasher)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Inside the &lt;code&gt;hash&lt;/code&gt; function, call the hasher’s &lt;code&gt;combine&lt;/code&gt; function for each property in your struct or class. Supply the name of the property.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hash&lt;/span&gt;(into hasher: &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; Hasher) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  hasher.combine(id)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// Call hasher.combine() for each property &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// in your data structure.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;addthe.ondeletecommandhandlertothelist&#34;&gt;Add the .onDeleteCommand Handler to the List&lt;/h3&gt;&#xA;&lt;p&gt;The last step is to remove the item from the list. Add the &lt;code&gt;.onDeleteCommand&lt;/code&gt; handler to the list to enable the Delete menu item in the Edit menu. Inside the block of code, you will use the selection variable you added to the list view to find the selection index. Use the selection index to remove the item from the list.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.onDeleteCommand {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; selection = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.selection,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; selectionIndex = book.chapters.firstIndex(of: selection) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    book.chapters.remove(at: selectionIndex)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;firstIndex&lt;/code&gt; function returns the first selected item in the list. After getting the index of the selected item, remove that item from the array that populates the list.&lt;/p&gt;&#xA;&lt;p&gt;Now let’s put the whole list view together.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;book.chapters) { &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;chapter &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  NavigationLink(destination: ChapterView(chapter: chapter), &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tag: chapter, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    selection: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;selection) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TextField(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, text: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;chapter.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.onDeleteCommand {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; selection = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.selection,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; selectionIndex = book.chapters.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      firstIndex(of: selection) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    book.chapters.remove(at: selectionIndex)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;removinganitemwithabuttonandthedeletekey&#34;&gt;Removing an Item with a Button and the Delete Key&lt;/h3&gt;&#xA;&lt;p&gt;At this point you can remove a list item by choosing Edit &amp;gt; Delete. But you may want to provide a button to remove an item. How do you remove list items by clicking a button?&lt;/p&gt;&#xA;&lt;p&gt;Start by moving the code inside the &lt;code&gt;.onDeleteCommand&lt;/code&gt; handler into its own function. Moving the deletion code into a separate function will also make the list code cleaner.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;deleteChapter&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; selection = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.selection,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; selectionIndex = book.chapters.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      firstIndex(of: selection) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    book.chapters.remove(at: selectionIndex)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the &lt;code&gt;.onDeleteCommand&lt;/code&gt; handler looks like the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.onDeleteCommand {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  deleteChapter()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Call the function in your button. Add a &lt;code&gt;.keyboardShortcut&lt;/code&gt; handler to the button to remove list items with the Delete (Backspace) key.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Button(action: { &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  deleteChapter() &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}, label: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Label(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Delete&amp;#34;&lt;/span&gt;, systemImage: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;trash&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .foregroundColor(.red)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.keyboardShortcut(.delete, modifiers: [])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I haven’t figured out how to add a keyboard shortcut for the Delete menu item in the Edit menu. Every example I’ve seen on creating keyboard shortcuts for menu items in SwiftUI uses custom menu items, not the menu items that Apple supplies. I’ll update the article if I ever find a solution.&lt;/p&gt;&#xA;&lt;h3 id=&#34;sampleproject&#34;&gt;Sample Project&lt;/h3&gt;&#xA;&lt;p&gt;I have a &lt;a href=&#34;https://github.com/SwiftDevJournal/MacWikiDemo&#34;&gt;project on GitHub&lt;/a&gt; that supports removing items from lists. Look at the &lt;code&gt;PageListView.swift&lt;/code&gt; and &lt;code&gt;Wiki.swift&lt;/code&gt; files for the list removal code.&lt;/p&gt;&#xA;&lt;p&gt;Another sample project for SwiftUI list item removal is the &lt;a href=&#34;https://github.com/trozware/feedread&#34;&gt;Feed Read project&lt;/a&gt; by &lt;a href=&#34;https://troz.net&#34;&gt;TrozWare&lt;/a&gt; for the &lt;a href=&#34;https://backtomac.org&#34;&gt;Back to the Mac conference&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Storing an Array of Custom Structs in Core Data</title>
      <link>https://swiftdevjournal.com/storing-an-array-of-custom-structs-in-core-data/</link>
      <pubDate>Wed, 23 Jun 2021 18:35:47 +0000</pubDate>
      <guid>https://swiftdevjournal.com/storing-an-array-of-custom-structs-in-core-data/</guid>
      <description>&lt;p&gt;A common question I see online about Core Data involves storing arrays. You have an array of a custom struct or class that you want to store in Core Data. Your initial instinct is to create an attribute for the array in your Core Data entity. But you discover that none of the available attribute types work. How do you store the array?&lt;/p&gt;&#xA;&lt;h3 id=&#34;thesolution:createato-manyrelationship&#34;&gt;The Solution: Create a To-Many Relationship&lt;/h3&gt;&#xA;&lt;p&gt;There are two steps to storing an array of a custom struct or class in Core Data. The first step is to create a Core Data entity for your custom struct or class.&lt;/p&gt;&#xA;&lt;p&gt;The second step is to add a to-many relationship in the Core Data entity where you want to store the array. The destination for the relationship is the entity you created for the custom struct or class. The to-many relationship holds the array items. Saving the main entity, the entity where you want to store the array, will save the array items.&lt;/p&gt;&#xA;&lt;p&gt;Keep in mind that Core Data uses sets to store to-many relationships instead of arrays. Each item that Core Data stores must be unique. Each element of a set must also be unique, which is why Core Data uses sets.&lt;/p&gt;&#xA;&lt;h3 id=&#34;asimpleexample&#34;&gt;A Simple Example&lt;/h3&gt;&#xA;&lt;p&gt;Let’s look at a simple example of creating a to-many relationship. Suppose you have a &lt;code&gt;Note&lt;/code&gt; entity and you want to store a list of each note’s tags. Start by creating a &lt;code&gt;Tag&lt;/code&gt; entity and adding the attributes you want a tag to have.&lt;/p&gt;&#xA;&lt;p&gt;After creating the &lt;code&gt;Tag&lt;/code&gt; entity, select the &lt;code&gt;Note&lt;/code&gt; entity in Xcode’s data model editor and add a relationship. Name the relationship &lt;code&gt;tags&lt;/code&gt;. Choose Tag as the destination.&lt;/p&gt;&#xA;&lt;p&gt;When you select the relationship, the data model inspector should be visible on the right side of the project window. Choose To Many from the Type menu. The relationship must be to-many to store a set (array) of items.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SetToManyRelationship.png&#34; alt=&#34;set to-many relationship&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the Ordered checkbox if you need the relationship items to be in a specific order.&lt;/p&gt;&#xA;&lt;p&gt;After creating the relationship each note has a list of tags. With the right controls in the app, you can add and remove tags. When you save a note Core Data also saves the tags.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Resources for Learning Combine</title>
      <link>https://swiftdevjournal.com/resources-for-learning-combine/</link>
      <pubDate>Thu, 22 Apr 2021 18:37:13 +0000</pubDate>
      <guid>https://swiftdevjournal.com/resources-for-learning-combine/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://developer.apple.com/documentation/combine&#34;&gt;Combine&lt;/a&gt; is Apple’s framework for handling asynchronous events in Swift. Combine and SwiftUI are the future for making iOS and Mac apps. This post lists resources for learning Combine.&lt;/p&gt;&#xA;&lt;h3 id=&#34;books&#34;&gt;Books&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Joseph Heck’s &lt;a href=&#34;https://heckj.github.io/swiftui-notes/&#34;&gt;Using Combine&lt;/a&gt; is freely available online.&lt;/li&gt;&#xA;&lt;li&gt;Daniel Steinberg’s &lt;a href=&#34;https://gumroad.com/l/combineKickstart&#34;&gt;A Combine Kickstart&lt;/a&gt; provides a nice introduction to Combine.&lt;/li&gt;&#xA;&lt;li&gt;Donny Wals’s &lt;a href=&#34;https://gumroad.com/l/practical-combine&#34;&gt;Practical Combine&lt;/a&gt; provides many practical examples of using Combine.&lt;/li&gt;&#xA;&lt;li&gt;Ray Wenderlich’s &lt;a href=&#34;https://www.raywenderlich.com/books/combine-asynchronous-programming-with-swift/v2.0&#34;&gt;Combine: Asynchronous Programming with Combine&lt;/a&gt; is a comprehensive resource for Combine.&lt;/li&gt;&#xA;&lt;li&gt;Mark Moeykens’ &lt;a href=&#34;https://www.bigmountainstudio.com/combine&#34;&gt;Combine Mastery in SwiftUI&lt;/a&gt; provides a visual guide to learning Combine with SwiftUI.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;websites&#34;&gt;Websites&lt;/h3&gt;&#xA;&lt;p&gt;I don’t know of any websites focused solely on Combine, but the following websites have articles on Combine:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.avanderlee.com&#34;&gt;Antoine van der Lee&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.donnywals.com/the-blog/&#34;&gt;Donny Wals&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftbysundell.com&#34;&gt;John Sundell&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Saving Data When Your Swift App Quits</title>
      <link>https://swiftdevjournal.com/saving-data-when-your-app-quits/</link>
      <pubDate>Mon, 12 Apr 2021 17:48:34 +0000</pubDate>
      <guid>https://swiftdevjournal.com/saving-data-when-your-app-quits/</guid>
      <description>&lt;p&gt;A common scenario for iOS and Mac apps is to save data when someone quits the app. You have written a function to save the data. Where do you make the call when the app quits? This article answers that question, both for the SwiftUI app life cycle and the classic AppDelegate life cycle.&lt;/p&gt;&#xA;&lt;h3 id=&#34;usingtheswiftuiapplifecycle&#34;&gt;Using the SwiftUI App Life Cycle&lt;/h3&gt;&#xA;&lt;p&gt;In Xcode 12 Apple introduced a native SwiftUI app life cycle. The new life cycle has a &lt;code&gt;scenePhase&lt;/code&gt; environment value that stores the app’s current phase, such as active, inactive, or background.&lt;/p&gt;&#xA;&lt;p&gt;Add a property to the app struct for the scene phase. Add the &lt;code&gt;.onChange&lt;/code&gt; modifier to the app’s window group or document group. Check if the phase is &lt;code&gt;.background&lt;/code&gt;. If it is, make a call to save the data. The following code shows how to check when the app goes in the background:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MySwiftUIApp&lt;/span&gt;: App {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @Environment(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.scenePhase) &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; scenePhase&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some Scene {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    WindowGroup {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ContentView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .onChange(of: scenePhase) { phase &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; phase == .background {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Save here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      } &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;usingtheappdelegatelifecycle&#34;&gt;Using the AppDelegate Life Cycle&lt;/h3&gt;&#xA;&lt;p&gt;If your Xcode project has a file named &lt;code&gt;AppDelegate.swift&lt;/code&gt;, it is using the AppDelegate life cycle. Open the &lt;code&gt;AppDelegate.swift&lt;/code&gt; function, and you should see multiple empty functions for handling app events.&lt;/p&gt;&#xA;&lt;p&gt;An iOS app that wants to save when someone quits the app should make a call to save the data in the function &lt;code&gt;applicationDidEnterBackground&lt;/code&gt;. This function is called when the person quits your app.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;applicationDidEnterBackground&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; application: UIApplication) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Save here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A Mac app should make the save call in &lt;code&gt;applicationWillTerminate&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;applicationWillTerminate&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; aNotification: Notification) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Save here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Xcode Installation Questions</title>
      <link>https://swiftdevjournal.com/xcode-installation-questions/</link>
      <pubDate>Mon, 05 Apr 2021 17:58:43 +0000</pubDate>
      <guid>https://swiftdevjournal.com/xcode-installation-questions/</guid>
      <description>&lt;p&gt;People learning iOS development without prior programming experience have a lot of questions on installing Xcode, Apple’s tool for developing iOS and Mac apps. This post collects these questions and answers them.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wheredoigetxcode&#34;&gt;Where do I get Xcode?&lt;/h3&gt;&#xA;&lt;p&gt;The easiest way to install Xcode is from the Mac App Store. The Mac App Store has the latest version, which usually requires the latest version of macOS.&lt;/p&gt;&#xA;&lt;p&gt;If your Mac can’t run the latest version of Xcode, go to &lt;a href=&#34;https://developer.apple.com/xcode/resources/&#34;&gt;Apple’s Xcode Downloads page&lt;/a&gt; and install an older version. You can also use the Downloads page to install the latest version if you run into problems with the Mac App Store.&lt;/p&gt;&#xA;&lt;p&gt;A faster way to find Xcode download links is to go to &lt;a href=&#34;https://xcodereleases.com&#34;&gt;Xcode Releases&lt;/a&gt;, a site that has download links for every version of Xcode. Xcode Releases also lists the minimum version of macOS required for each Xcode version.&lt;/p&gt;&#xA;&lt;p&gt;Another alternative to the App Store is to use the &lt;a href=&#34;https://github.com/XcodesOrg/XcodesApp&#34;&gt;Xcodes app&lt;/a&gt; to install Xcode. I have not used Xcodes, but many people swear by it, saying it installs Xcode much faster than the App Store.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whydoesxcodetakeforevertoinstall&#34;&gt;Why does Xcode take forever to install?&lt;/h3&gt;&#xA;&lt;p&gt;Xcode is a huge app. Verifying and expanding it takes a really long time. Even with a fast Internet connection, it will take 1–2 hours to install Xcode.&lt;/p&gt;&#xA;&lt;p&gt;A &lt;a href=&#34;https://twitter.com/_saagarjha/status/1481353292164698112&#34;&gt;Twitter thread&lt;/a&gt; explains why expanding takes so much time and provides a tip to speed up the expanding.&lt;/p&gt;&#xA;&lt;p&gt;If you are installing Xcode from the Mac App Store, you can see the progress of the install from the LaunchPad app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whydoesapplesayidonthaveenoughdiskspacetoinstallxcode&#34;&gt;Why does Apple say I don’t have enough disk space to install Xcode?&lt;/h3&gt;&#xA;&lt;p&gt;Xcode requires a lot of disk space to install. You need 4–5 times the size of the Xcode download to install it. The file you are downloading is a compressed file. You need enough free space to temporarily store both the compressed and expanded files. If you have a Mac with a 128 GB drive, you will have a tough time installing Xcode.&lt;/p&gt;&#xA;&lt;p&gt;If you get an error message saying there isn’t enough free space to install Xcode, free up more disk space until the error message goes away.&lt;/p&gt;&#xA;&lt;p&gt;Some ways to free up disk space and work around space limitations include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Download Xcode from the &lt;a href=&#34;https://xcodereleases.com&#34;&gt;Xcode Releases site&lt;/a&gt; onto an external drive and expand it there. Copy the expanded file to your main drive.&lt;/li&gt;&#xA;&lt;li&gt;Restarting your Mac can free up disk space if you haven’t restarted the Mac in several days.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;a href=&#34;https://apps.apple.com/us/app/devcleaner-for-xcode/id1388020431?mt=12&#34;&gt;Dev Cleaner app&lt;/a&gt; can free up space used by Xcode caches and old iOS simulators.&lt;/li&gt;&#xA;&lt;li&gt;Delete existing versions of Xcode before installing a new version.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;caniinstallxcodeonanexternaldrive&#34;&gt;Can I install Xcode on an external drive?&lt;/h3&gt;&#xA;&lt;p&gt;Xcode must be installed on your Mac’s startup disk. If you make an external drive the startup disk, you can install Xcode on an external drive. Use the System Preferences app (Choose Apple &amp;gt; System Preferences from the menu bar) to set the startup disk.&lt;/p&gt;&#xA;&lt;h3 id=&#34;canirunxcodeonanipad&#34;&gt;Can I run Xcode on an iPad?&lt;/h3&gt;&#xA;&lt;p&gt;Xcode currently runs only on Macs. Apple has a &lt;a href=&#34;https://apps.apple.com/us/app/swift-playgrounds/id908519492&#34;&gt;Swift Playgrounds app&lt;/a&gt; for iPad to learn Swift programming. Version 4, which requires iOS 15, lets you develop iOS apps on an iPad.&lt;/p&gt;&#xA;&lt;h3 id=&#34;canirunxcodeonawindowspc&#34;&gt;Can I run Xcode on a Windows PC?&lt;/h3&gt;&#xA;&lt;p&gt;Not without violating Apple’s license on macOS. Xcode currently runs only on macOS. Apple’s license forbids installing macOS on non-Apple hardware.&lt;/p&gt;&#xA;&lt;h3 id=&#34;canihavemultipleversionsofxcodeonmymac&#34;&gt;Can I have multiple versions of Xcode on my Mac?&lt;/h3&gt;&#xA;&lt;p&gt;Yes you can.&lt;/p&gt;&#xA;&lt;p&gt;If you are installing Xcode from the Mac App Store, make sure you don’t overwrite your existing Xcode install. When installing from the Mac App Store, Apple adds a file named Xcode in your Applications folder. Change the name of the existing Xcode app on your Mac before installing the new version.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Where are the Single View and Master-Detail App Project Templates?</title>
      <link>https://swiftdevjournal.com/where-are-the-single-view-and-master-detail-app-project-templates/</link>
      <pubDate>Mon, 15 Feb 2021 19:53:03 +0000</pubDate>
      <guid>https://swiftdevjournal.com/where-are-the-single-view-and-master-detail-app-project-templates/</guid>
      <description>&lt;p&gt;Prior to Xcode 12 Xcode had the following iOS application project templates:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Single View App&lt;/li&gt;&#xA;&lt;li&gt;Master-Detail App&lt;/li&gt;&#xA;&lt;li&gt;Page-Based App&lt;/li&gt;&#xA;&lt;li&gt;Tabbed App&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you create an iOS application project in Xcode 12, you will notice these project templates are missing. In Xcode 12 Apple consolidated these project templates into one template: App. If you are following a tutorial that tells you to choose one of the older templates that no longer exist, choose the App template.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Using Environment Variables in Swift Apps</title>
      <link>https://swiftdevjournal.com/using-environment-variables-in-swift-apps/</link>
      <pubDate>Mon, 25 Jan 2021 19:44:04 +0000</pubDate>
      <guid>https://swiftdevjournal.com/using-environment-variables-in-swift-apps/</guid>
      <description>&lt;h3 id=&#34;whentouseenvironmentvariables&#34;&gt;When to Use Environment Variables&lt;/h3&gt;&#xA;&lt;p&gt;Most Swift apps do not need environment variables. A common reason to use environment variables is for apps that call a website’s REST APIs. To gain access to someone’s account on the website, your Swift app uses a client ID and client secret from the website. Storing the client ID and client secret in environment variables is safer than storing them as strings in your code.&lt;/p&gt;&#xA;&lt;p&gt;Suppose you are developing a git client app. Your app wants to push commits to GitHub. To push commits to GitHub you must create an OAuth app for your app in GitHub. The GitHub OAuth app contains a client ID and a client secret that your Swift app uses to authenticate the user so your Swift app can access the person’s GitHub account. &lt;a href=&#34;https://docs.github.com/en/developers/github-marketplace/security-best-practices-for-apps&#34;&gt;GitHub recommends using environment variables to store the client ID and client secret&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addtheenvironmentvariablesfromxcodesschemeeditor&#34;&gt;Add the Environment Variables from Xcode’s Scheme Editor&lt;/h3&gt;&#xA;&lt;p&gt;The first step to using environment variables is to add them to your Xcode project. Use Xcode’s scheme editor to add environment variables to your app. Use the jump bar next to the Run and Stop buttons in the project window toolbar to open the scheme editor.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeSetEnvironmentVariablesBlurred.png&#34; alt=&#34;Xcode set environment variables&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the Run step on the left side of the scheme editor. Click the Arguments button at the top of the scheme editor to access the environment variables. Use the Add (+) button to add the environment variables.&lt;/p&gt;&#xA;&lt;h3 id=&#34;accessingenvironmentvariablesinyourswiftcode&#34;&gt;Accessing Environment Variables in Your Swift Code&lt;/h3&gt;&#xA;&lt;p&gt;After adding environment variables, you can access them in your code. Use the &lt;code&gt;ProcessInfo&lt;/code&gt; class to access environment variables. The class has a &lt;code&gt;processInfo&lt;/code&gt; property that contains a dictionary of values. The name of the environment variable is a key in the dictionary. Use that key to get the environment variable’s value. The following code demonstrates how to access a variable containing a GitHub OAuth app’s client ID:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; clientID = ProcessInfo.processInfo.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  environment[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GITHUB_CLIENT_ID&amp;#34;&lt;/span&gt;] {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Should I learn Swift or SwiftUI?</title>
      <link>https://swiftdevjournal.com/should-i-learn-swift-or-swiftui/</link>
      <pubDate>Mon, 11 Jan 2021 05:02:19 +0000</pubDate>
      <guid>https://swiftdevjournal.com/should-i-learn-swift-or-swiftui/</guid>
      <description>&lt;p&gt;I see a lot of new iOS developers ask the question in the title of this article. The short answer is both. To write SwiftUI apps you must also learn Swift because Swift is the programming language SwiftUI uses. The rest of this article provides a more detailed explanation.&lt;/p&gt;&#xA;&lt;h3 id=&#34;uikit&#34;&gt;UIKit&lt;/h3&gt;&#xA;&lt;p&gt;In 2008 Apple gave developers a SDK (Software Development Kit) to let them make native iOS apps. The heart of the SDK was UIKit, a framework for creating the views and controls in iOS apps, such as buttons, text fields, and table views.&lt;/p&gt;&#xA;&lt;p&gt;UIKit uses the Objective-C programming language. Using Objective-C worked well for existing Mac developers, who were already using Objective-C to make Mac apps. But the release of the iOS SDK attracted lots of new developers to the Apple developer community. These new developers found Objective-C’s syntax to look strange and found it difficult to understand. They wanted a language with a syntax that looked more familiar.&lt;/p&gt;&#xA;&lt;h3 id=&#34;swift&#34;&gt;Swift&lt;/h3&gt;&#xA;&lt;p&gt;In 2014 Apple unveiled their solution for developers who hated Objective-C: the Swift programming language. Swift’s syntax looked more familiar to people who came to iOS development from web development and Windows development. Now iOS developers had two language choices for making iOS apps with UIKit: Swift and Objective-C.&lt;/p&gt;&#xA;&lt;h3 id=&#34;swiftui&#34;&gt;SwiftUI&lt;/h3&gt;&#xA;&lt;p&gt;In 2019 Apple released the initial version of SwiftUI, a new framework for developing apps for all of Apple platforms: iOS, Mac, tvOS, and watchOS. SwiftUI has only one language: Swift. You must know Swift to use SwiftUI.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thelanguageandframeworkoptionsforiosapps&#34;&gt;The Language and Framework Options for iOS Apps&lt;/h3&gt;&#xA;&lt;p&gt;Someone who wants to make iOS apps with Apple’s frameworks has three options.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Use UIKit with Objective-C.&lt;/li&gt;&#xA;&lt;li&gt;Use UIKit with Swift.&lt;/li&gt;&#xA;&lt;li&gt;Use SwiftUI with Swift.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Which option should use choose? You won’t be making a mistake no matter which option you choose. But for someone new to iOS development, I recommend Option 3, write the app with SwiftUI using Swift. SwiftUI is the future of iOS development. You’re eventually going to have to learn it so you might as well learn it now.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Getting Started with Swift Unit Testing in Xcode</title>
      <link>https://swiftdevjournal.com/getting-started-with-swift-unit-testing-in-xcode/</link>
      <pubDate>Tue, 15 Dec 2020 19:05:21 +0000</pubDate>
      <guid>https://swiftdevjournal.com/getting-started-with-swift-unit-testing-in-xcode/</guid>
      <description>&lt;p&gt;In this article you’ll learn what you need to start unit testing your Swift code in Xcode.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addingaunittesttargettoyourxcodeproject&#34;&gt;Adding a Unit Test Target to Your Xcode Project&lt;/h3&gt;&#xA;&lt;p&gt;To unit test your app, your Xcode project must have a unit test target. The easiest way to add a unit test target to your project is to select the Include Tests checkbox when you create the project. Selecting the checkbox creates targets for unit tests and UI tests.&lt;/p&gt;&#xA;&lt;p&gt;To add a unit test target to an existing Xcode project, choose File &amp;gt; New &amp;gt; Target.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AddUnitTestingTarget.png&#34; alt=&#34;add unit test target&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select your app platform (iOS, macOS, watchOS, tvOS) from the top of the New Target Assistant. Select the Unit Testing Bundle target from the list of targets. You will have to scroll through a long list of application extension targets to find the test targets.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addingaunittestclasstoyourxcodeproject&#34;&gt;Adding a Unit Test Class to Your Xcode Project&lt;/h3&gt;&#xA;&lt;p&gt;When you create the unit test target, Xcode includes a unit test class file. It has the name &lt;code&gt;AppNameTests.swift&lt;/code&gt;, where AppName is the name of your project. Unless you have a really small project, you will have multiple unit test classes.&lt;/p&gt;&#xA;&lt;p&gt;Choose File &amp;gt; New &amp;gt; File to add a new file to your project.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AddUnitTestClass.png&#34; alt=&#34;add unit test class&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select Unit Test Case Class from the list of file templates. Click the Next button.&lt;/p&gt;&#xA;&lt;p&gt;Enter the name of the class in the Class text field. The subclass should be set to &lt;code&gt;XCTestCase&lt;/code&gt;, and the language should be set to Swift. Click the Next button.&lt;/p&gt;&#xA;&lt;p&gt;Save the file inside the Tests folder. Make sure to select the checkbox for the unit test target.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AddUnitTestClassToTarget.png&#34; alt=&#34;add unit test class to target&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the Create button to finish creating the unit test class.&lt;/p&gt;&#xA;&lt;h3 id=&#34;theinitialunittestclass&#34;&gt;The Initial Unit Test Class&lt;/h3&gt;&#xA;&lt;p&gt;Select the unit test class’s Swift file to open it. It should look similar to the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;XCTest&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@testable &lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Scrumdinger&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ScrumdingerTests&lt;/span&gt;: XCTestCase {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setUpWithError&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Put setup code here. This method is called before the invocation of each test method in the class.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tearDownWithError&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Put teardown code here. This method is called after the invocation of each test method in the class.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;testExample&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// This is an example of a functional test case.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Use XCTAssert and related functions to verify your tests produce the correct results.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;testPerformanceExample&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// This is an example of a performance test case.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.measure {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Put the code you want to measure the time of here.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first two lines of code import the XCTest framework, which is the framework Xcode uses for unit testing Swift code, and your app. You must use the &lt;code&gt;@testable import&lt;/code&gt; statement to give the unit test class access to your app’s code. If your app name has spaces in it, use the underscore character instead of spaces in the &lt;code&gt;@testable import&lt;/code&gt; call.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@testable &lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;My_App_Name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next comes the declaration of the unit test class. It inherits from &lt;code&gt;XCTestCase&lt;/code&gt;, the base class for Xcode’s unit test classes.&lt;/p&gt;&#xA;&lt;p&gt;Finally comes the four empty test methods.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The &lt;code&gt;setUpWithError&lt;/code&gt; method gets called before running each test in the class. Put any setup code you need to run before each test in this method.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;tearDownWithError&lt;/code&gt; method gets called after each test runs.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;testExample&lt;/code&gt; method provides a shell for a unit test. You can delete this method.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;textPerformanceExample&lt;/code&gt; method provides a shell for a performance unit test. You can delete this method.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The &lt;code&gt;throws&lt;/code&gt; keyword means the test method throws an exception if the test fails.&lt;/p&gt;&#xA;&lt;p&gt;Older versions of Xcode may not have the &lt;code&gt;throws&lt;/code&gt; keyword in the test methods. The setup and teardown methods may not have the &lt;code&gt;WithError&lt;/code&gt; part at the end.&lt;/p&gt;&#xA;&lt;h3 id=&#34;xctesttestmethods&#34;&gt;XCTest Test Methods&lt;/h3&gt;&#xA;&lt;p&gt;Each unit test requires you to write a method for it. A unit test method has the following requirements:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;It must start with the word &lt;code&gt;test&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;It takes no arguments.&lt;/li&gt;&#xA;&lt;li&gt;It returns no value.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The following code shows the definition of a unit test method:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;testMyExample&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the test start by calling the code in your app that you want to test. Then make an assertion, which I talk about next.&lt;/p&gt;&#xA;&lt;h3 id=&#34;xctestassertions&#34;&gt;XCTest Assertions&lt;/h3&gt;&#xA;&lt;p&gt;Each test needs at least one assertion, which determines whether or not the test passes. XCTest assertions start with &lt;code&gt;XCTAssert&lt;/code&gt;. If you start typing &lt;code&gt;XCTAssert&lt;/code&gt;, Xcode’s code completion should show you a list of all the available assertions, but the following are the most widely-used assertions:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;XCTAssertNotNil&lt;/code&gt; asserts a variable is not nil.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;XCTAssertTrue&lt;/code&gt; asserts a condition is true.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;XCTAssertFalse&lt;/code&gt; asserts a condition is false.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;XCTAssertEqual&lt;/code&gt; asserts two values are equal.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The simplest way to write an assertion is to supply an expression.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;XCTAssertTrue(temperature &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But when you supply only the expression, all you get when a test fails is a message that the test failed. In this assertion example, when the assertion fails, you would like to know what the value of &lt;code&gt;temperature&lt;/code&gt; is. Supply an error message to report as the final argument in the assertion. Wrap the variable whose value you want to report using the following syntax:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;(variableName)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following shows an improved assertion that the temperature is above 0.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;XCTAssertTrue(temperature &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The temperature should be &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  above 0. Temperature: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;temperature&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;runningunittests&#34;&gt;Running Unit Tests&lt;/h3&gt;&#xA;&lt;p&gt;Xcode provides multiple ways to run your tests.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Press Cmd-U to run all your tests.&lt;/li&gt;&#xA;&lt;li&gt;Run a unit test class’s tests from the Xcode editor by clicking the diamond-shaped button on the left side of the editor next to the test class name.&lt;/li&gt;&#xA;&lt;li&gt;Run a single test from Xcode’s editor by clicking the diamond-shaped button next to the test method.&lt;/li&gt;&#xA;&lt;li&gt;Press Cmd–6 to open the test navigator. Selecting the test target, a test class, or a test will make a small button appear on the right side of the navigator. Click the button to run the target’s tests, the class’s tests, or the single test, depending on what you selected.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;unittestingchecklist&#34;&gt;Unit Testing Checklist&lt;/h3&gt;&#xA;&lt;p&gt;Use the following checklist to start unit testing your Swift code in Xcode:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a unit test target by selecting the Include Tests checkbox when creating your Xcode project.&lt;/li&gt;&#xA;&lt;li&gt;Add unit test classes to the test target by choosing File &amp;gt; New &amp;gt; File.&lt;/li&gt;&#xA;&lt;li&gt;Import the XCTest framework in your unit test classes.&lt;/li&gt;&#xA;&lt;li&gt;Use the &lt;code&gt;@testable import&lt;/code&gt; statement to give your unit test classes access to your app’s code.&lt;/li&gt;&#xA;&lt;li&gt;Add test methods to your unit test classes.&lt;/li&gt;&#xA;&lt;li&gt;Test methods start with &lt;code&gt;test&lt;/code&gt;, take no arguments, and return no value.&lt;/li&gt;&#xA;&lt;li&gt;Add at least one XCTest assertion in your test methods.&lt;/li&gt;&#xA;&lt;li&gt;Press Cmd-U to run the tests.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Make a Markdown Editor in SwiftUI</title>
      <link>https://swiftdevjournal.com/make-a-markdown-editor-in-swiftui/</link>
      <pubDate>Mon, 23 Nov 2020 19:43:37 +0000</pubDate>
      <guid>https://swiftdevjournal.com/make-a-markdown-editor-in-swiftui/</guid>
      <description>&lt;p&gt;In this tutorial you will make a Markdown editor with live preview using SwiftUI. This editor will run on both iOS and Mac. It’s a nice example to demonstrate how to create a document-based, multi-platform SwiftUI app. Plus, it shows how to use a WebKit web view in SwiftUI.&lt;/p&gt;&#xA;&lt;p&gt;This tutorial uses the new document-based app features Apple added in Xcode 12. You must be running Xcode 12.2+ to create a multi-platform SwiftUI app. The iOS app requires iOS 14+, and the Mac app requires macOS 11+. If you are running macOS 10.15 (Catalina) on your Mac, you can still make the editor. You won’t be able to run the Mac version.&lt;/p&gt;&#xA;&lt;p&gt;To keep the tutorial from getting too long, I will gloss over some steps and explanations that I covered in the following articles:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/using-text-views-in-a-swiftui-app/&#34;&gt;Using Text Views in a SwiftUI App&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/create-a-mac-markdown-editor-with-live-preview/&#34;&gt;Create a Mac Markdown Editor with Live Preview&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/introducing-the-swift-package-manager/&#34;&gt;Introducing the Swift Package Manager&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;createtheproject&#34;&gt;Create the Project&lt;/h3&gt;&#xA;&lt;p&gt;Start by creating the project.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Choose File &amp;gt; New &amp;gt; Project in Xcode.&lt;/li&gt;&#xA;&lt;li&gt;Click the Multiplatform button at the top of the New Project Assistant.&lt;/li&gt;&#xA;&lt;li&gt;Choose Document App from the list of application templates.&lt;/li&gt;&#xA;&lt;li&gt;Click the Next button.&lt;/li&gt;&#xA;&lt;li&gt;Name the project in the Product Name text field.&lt;/li&gt;&#xA;&lt;li&gt;Click the Next button.&lt;/li&gt;&#xA;&lt;li&gt;Choose a location to save the project.&lt;/li&gt;&#xA;&lt;li&gt;Click the Create button.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;If you look at the project navigator, you will see Xcode creates the following folders for your project:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The Shared folder contains files that both the iOS and Mac app targets use.&lt;/li&gt;&#xA;&lt;li&gt;The iOS folder contains files that the iOS app uses.&lt;/li&gt;&#xA;&lt;li&gt;The Mac folder contains files that the Mac app uses.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In the Shared folder are Swift files for the app, document, and content view.&lt;/p&gt;&#xA;&lt;p&gt;Run the project and you will see that you have a working plain text editor. You can create documents, edit text, save documents, and load documents.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addtheinkpackage&#34;&gt;Add the Ink Package&lt;/h3&gt;&#xA;&lt;p&gt;This project uses the &lt;a href=&#34;https://github.com/JohnSundell/Ink&#34;&gt;Ink Markdown parser&lt;/a&gt; to convert the Markdown you type in the text editor to HTML that you will preview. Ink has Swift Package Manager support to simplify adding it to your Xcode project.&lt;/p&gt;&#xA;&lt;p&gt;Select the name of your project from the project navigator to open the project editor. Select the project from the project editor and click the Swift Packages button at the top of the editor to add the Ink package.&lt;/p&gt;&#xA;&lt;p&gt;A current limitation in Xcode’s Swift Package Manager support is you can add a package to only one target initially. To add Ink to the other app target, select the target from the project editor and add the Ink framework from the Frameworks, Libraries, and Embedded Content section.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AddSwiftPackageToSecondTarget.png&#34; alt=&#34;add package to second target&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;addwebviews&#34;&gt;Add Web Views&lt;/h3&gt;&#xA;&lt;p&gt;To preview the Markdown you write, you need a web view to display the HTML. SwiftUI does not currently have a native web view so you must use a WebKit web view, &lt;code&gt;WKWebView&lt;/code&gt;, for the preview.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;WKWebView&lt;/code&gt; has both iOS and Mac support, but you’re going to have to create two web view files: one for the iOS app and one for the Mac app. The code is going to be almost identical. The reason you need two files is that SwiftUI has separate protocols for working with UIKit(iOS) and AppKit(Mac) views.&lt;/p&gt;&#xA;&lt;p&gt;Create one new Swift file in the iOS folder in the project navigator and create a second file in the Mac folder. Make sure the file in the iOS folder is a member of the iOS app target. Make sure the file in the Mac folder is a member of the Mac app target. You can set the target membership for a file using the File Inspector on the right side of the project window.&lt;/p&gt;&#xA;&lt;p&gt;Add the following code to the iOS Swift file:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SwiftUI&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WebKit&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WebView&lt;/span&gt;: UIViewRepresentable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; html: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(html: String) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.html = html&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeUIView&lt;/span&gt;(context: Context) -&amp;gt; WKWebView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; webView = WKWebView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; webView&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateUIView&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; uiView: WKWebView, context: Context) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    uiView.loadHTMLString(html, baseURL: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The web view uses the SwiftUI and WebKit frameworks so you must import them. When you use a UIKit view in a SwiftUI app, the view must conform to the &lt;code&gt;UIViewRepresentable&lt;/code&gt; protocol. The &lt;code&gt;html&lt;/code&gt; property stores the HTML to display in the web view.&lt;/p&gt;&#xA;&lt;p&gt;There are three functions. The &lt;code&gt;init&lt;/code&gt; function initializes the web view with some HTML to display. The &lt;code&gt;makeUIView&lt;/code&gt; function creates the web view. The &lt;code&gt;updateUIView&lt;/code&gt; function loads the HTML string to show in the web view.&lt;/p&gt;&#xA;&lt;p&gt;The Mac code is almost identical. Replace anything starting with UI with NS.&lt;/p&gt;&#xA;&lt;h3 id=&#34;parsingthemarkdown&#34;&gt;Parsing the Markdown&lt;/h3&gt;&#xA;&lt;p&gt;The next step is to write some code to parse the Markdown to HTML. Open the &lt;code&gt;ContentView.swift&lt;/code&gt; file. Import the Ink framework.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Ink&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the following computed property to the &lt;code&gt;ContentView&lt;/code&gt; struct:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; html: String {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; parser = MarkdownParser()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; parser.html(from: document.text)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code creates an Ink parser and calls a function that converts the document text into HTML. This code is much easier to write than creating your own Markdown parser.&lt;/p&gt;&#xA;&lt;h3 id=&#34;buildtheuserinterface&#34;&gt;Build the User Interface&lt;/h3&gt;&#xA;&lt;p&gt;The last step is to build the user interface. The user interface contains a text editor and a web view side by side.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;body&lt;/code&gt; property for the content view should look like the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  HStack {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TextEditor(text: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;document.text)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    WebView(html: html)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code creates a horizontal stack so the text editor and web view are side by side. The text editor is on the left and contains the document’s text. The web view is on the right and displays the HTML you parsed from the Markdown text. The iOS app uses the iOS version of the web view. The Mac app uses the Mac version of the web view.&lt;/p&gt;&#xA;&lt;p&gt;Run the project. Any Markdown you type in the text editor will appear as HTML in the web view. The Ink parser does not currently support creating code blocks with indentation. You must add three backticks on the line above and below the code to create a code block.&lt;/p&gt;&#xA;&lt;p&gt;I have &lt;a href=&#34;https://github.com/SwiftDevJournal/SwiftUIMarkdownEditor&#34;&gt;the project on GitHub&lt;/a&gt; for you to look at if you run into problems.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Renaming Xcode Projects</title>
      <link>https://swiftdevjournal.com/renaming-xcode-projects/</link>
      <pubDate>Mon, 19 Oct 2020 18:18:42 +0000</pubDate>
      <guid>https://swiftdevjournal.com/renaming-xcode-projects/</guid>
      <description>&lt;p&gt;Renaming Xcode projects is not intuitive or obvious. If you do it wrong, you can mess up your project. In this article you will learn how to safely rename your app and your project.&lt;/p&gt;&#xA;&lt;p&gt;I recommend placing your project under version control or backing up your project before you rename it. If something goes wrong during the rename, you can go back to the way your project was before. Read the following article to learn how to put your Xcode project under version control:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/putting-your-xcode-project-on-github-bitbucket-or-gitlab/&#34;&gt;Putting Your Xcode Project on GitHub, Bitbucket, or GitLab&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;renamethetargettorenametheapp&#34;&gt;Rename the Target to Rename the App&lt;/h3&gt;&#xA;&lt;p&gt;Most of the time when people want to rename their project, what they really want to do is rename their app. By renaming the app target, you can rename the app without having to rename the project.&lt;/p&gt;&#xA;&lt;p&gt;Select the project from the project navigator to open the project editor and see a list of the app’s targets.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/TargetList.png&#34; alt=&#34;target list&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;To rename a target, select it, press the Return key, and enter the new name. If all you want to do is rename the app, you’re finished.&lt;/p&gt;&#xA;&lt;h3 id=&#34;renamingtheproject&#34;&gt;Renaming the Project&lt;/h3&gt;&#xA;&lt;p&gt;Continue reading if you really want to rename the project. If you look at the screenshot from the previous section, you might think you could rename the project by selecting it and pressing the Return key. But you’ll discover that you can’t change the project name from the project editor.&lt;/p&gt;&#xA;&lt;p&gt;Use the project navigator to change the project name.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ChangeXcodeProjectName.png&#34; alt=&#34;change project name&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the project file and press Return to change the name. A sheet will open.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/RenameProjectSheet.png&#34; alt=&#34;rename project sheet&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Xcode is initially set to rename all the project’s targets to reflect the new name of the project. Deselect a checkbox next to any item you don’t want to rename. Click the Rename button to rename the project.&lt;/p&gt;&#xA;&lt;p&gt;Clicking the Don’t Rename button will rename the project file but won’t rename anything else.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>How to Notarize a Mac App</title>
      <link>https://swiftdevjournal.com/how-to-notarize-a-mac-app/</link>
      <pubDate>Thu, 08 Oct 2020 19:01:44 +0000</pubDate>
      <guid>https://swiftdevjournal.com/how-to-notarize-a-mac-app/</guid>
      <description>&lt;p&gt;Notarizing a Mac app allows it to work better with Apple’s Gatekeeper feature in macOS. If you do not notarize your app, when someone downloads the app and tries to run it, an alert will open saying the app is from an untrusted developer. This alert may make people afraid to run your app. Notarizing your app keeps that alert from appearing and makes it easier for people to run your app. In this article you will learn how to notarize your Mac app so you can distribute it from your own website.&lt;/p&gt;&#xA;&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;&#xA;&lt;p&gt;You must have a paid developer account with Apple to notarize apps.&lt;/p&gt;&#xA;&lt;p&gt;Your app must have the Hardened Runtime capability enabled to notarize it. Open the project editor and click the Signing &amp;amp; Capabilities button to see if you have enabled the Hardened Runtime capability&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Hardened-Runtime.png&#34; alt=&#34;hardened runtime&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;highlevelnotarizationsteps&#34;&gt;High Level Notarization Steps&lt;/h3&gt;&#xA;&lt;p&gt;Take the following steps to notarize your Mac app:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Archive your project in Xcode by choosing Product &amp;gt; Archive.&lt;/li&gt;&#xA;&lt;li&gt;Open Xcode’s Organizer window by choosing Window &amp;gt; Organizer.&lt;/li&gt;&#xA;&lt;li&gt;Select your archive from the list of archives.&lt;/li&gt;&#xA;&lt;li&gt;Distribute the app.&lt;/li&gt;&#xA;&lt;li&gt;Choose a distribution method.&lt;/li&gt;&#xA;&lt;li&gt;Choose a destination.&lt;/li&gt;&#xA;&lt;li&gt;Choose a code signing option.&lt;/li&gt;&#xA;&lt;li&gt;Review and upload.&lt;/li&gt;&#xA;&lt;li&gt;Wait for Apple to notarize.&lt;/li&gt;&#xA;&lt;li&gt;Export the notarized app.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;I will go into more detail on Steps 3–10 in the rest of the article.&lt;/p&gt;&#xA;&lt;h3 id=&#34;findingyourarchiveanddistributing&#34;&gt;Finding Your Archive and Distributing&lt;/h3&gt;&#xA;&lt;p&gt;In Xcode 12 the Organizer window looks similar to the following screenshot:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ArchiveListInOrganizer.png&#34; alt=&#34;organizer archive list&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;In the upper left window is a menu with a list of your archived apps. Choose your app from the list. Click the Archives item in the Organizer sidebar to see a list of archives for your app. Select an archive from the list.&lt;/p&gt;&#xA;&lt;p&gt;Click the Distribute App button on the right side of the Organizer to start the process of notarizing your app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;chooseadistributionmethod&#34;&gt;Choose a Distribution Method&lt;/h3&gt;&#xA;&lt;p&gt;When you click the Distribute App button, a sheet opens with a list of distribution methods.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DistributionMethod.png&#34; alt=&#34;distribution method&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;To notarize your app and upload it to your website, you should choose Developer ID. Click the Next button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;chooseadestination&#34;&gt;Choose a Destination&lt;/h3&gt;&#xA;&lt;p&gt;The next step is to choose a destination.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Destination.png&#34; alt=&#34;destination&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;There are two destination options: Upload and Export. You must choose Upload to notarize the app. Click the Next button.&lt;/p&gt;&#xA;&lt;p&gt;At this point, another sheet may appear with a checkbox to receive symbolicated crash reports from Apple. Select that checkbox and click the Next button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;chooseasigningoption&#34;&gt;Choose a Signing Option&lt;/h3&gt;&#xA;&lt;p&gt;Apple provides two methods to manage the signing of your app: Automatic and Manual.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SigningOptions.png&#34; alt=&#34;signing options&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I recommend automatically manage signing. Click the Next button.&lt;/p&gt;&#xA;&lt;p&gt;At this point you will be asked for your Mac user’s password. Enter it.&lt;/p&gt;&#xA;&lt;h3 id=&#34;reviewandupload&#34;&gt;Review and Upload&lt;/h3&gt;&#xA;&lt;p&gt;Now you can review options for notarizing the app.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ReviewContent.png&#34; alt=&#34;review content&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you find a mistake, click the Previous button to go back and fix the mistake. When things look good, click the Upload button to upload your app to Apple to notarize.&lt;/p&gt;&#xA;&lt;h3 id=&#34;waitforappletonotarize&#34;&gt;Wait for Apple to Notarize&lt;/h3&gt;&#xA;&lt;p&gt;If the upload is successful, Apple will send you an email when they finish notarizing the app. Normally notarizing takes 20–30 minutes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;exportthenotarizedapp&#34;&gt;Export the Notarized App&lt;/h3&gt;&#xA;&lt;p&gt;When the app is notarized, a button with the title Export Notarized App appears on the right side of the Organizer. You may need to scroll the window to see the button. Click that button to export the app to a location on your Mac. When you finish exporting, you can upload the app to your website for people to download.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Customizing the About Box in Your Mac App</title>
      <link>https://swiftdevjournal.com/customizing-the-about-box-in-your-mac-app/</link>
      <pubDate>Mon, 14 Sep 2020 18:41:25 +0000</pubDate>
      <guid>https://swiftdevjournal.com/customizing-the-about-box-in-your-mac-app/</guid>
      <description>&lt;p&gt;Every Mac app has an About box, which you can access by choosing AppName &amp;gt; About AppName. For a new Cocoa project, the About box looks similar to the following image:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AboutBoxBefore.png&#34; alt=&#34;about box before&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;How do you customize the About box? Add a file named &lt;code&gt;Credits.rtf&lt;/code&gt; to your project. Fill the file with your app credits. When you build the project, the text you entered in the RTF file will appear in a box between the version number and the copyright notice in the About box.&lt;/p&gt;&#xA;&lt;p&gt;Choose File &amp;gt; New &amp;gt; File in Xcode to add a new file to the project. The RTF File template is in the Resource section.&lt;/p&gt;&#xA;&lt;p&gt;Select the &lt;code&gt;Credits.rtf&lt;/code&gt; file to edit the credits.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreditsExample.png&#34; alt=&#34;credits example&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Now build your project and choose AppName &amp;gt; About. Your About box should look similar to the following screenshot:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AboutBoxAfter.png&#34; alt=&#34;about box after&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If your credits are not appearing in a white scroll view, make sure you make the text long enough to trigger the need for a scroll view. When I just added the developer credit in the screenshot, the Credits appeared without a scroll view, and it didn’t look good.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Working with Open and Save Panels in Mac Apps</title>
      <link>https://swiftdevjournal.com/working-with-open-and-save-panels-in-mac-apps/</link>
      <pubDate>Tue, 08 Sep 2020 18:05:09 +0000</pubDate>
      <guid>https://swiftdevjournal.com/working-with-open-and-save-panels-in-mac-apps/</guid>
      <description>&lt;p&gt;My &lt;a href=&#34;https://www.swiftdevjournal.com/changing-the-button-title-for-open-and-save-panels/&#34;&gt;short article on changing the button title for open and save panels&lt;/a&gt; gave me the idea to write a longer article on working with open and save panels.&lt;/p&gt;&#xA;&lt;h3 id=&#34;youmaynotneedtodealwithopenandsavepanels&#34;&gt;You May Not Need to Deal with Open and Save Panels&lt;/h3&gt;&#xA;&lt;p&gt;Apple’s document architecture gives you a lot of default behavior for free. You can write an app that opens and saves files without having to write any code for the open and save panels. The most common case of having to write code that involves open and save panels is importing and exporting data. For example an image editor would use a save panel to export the image to common file formats, such as GIF, JPEG, and PNG.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingthepanel&#34;&gt;Creating the Panel&lt;/h3&gt;&#xA;&lt;p&gt;Creating the open or save panel is the easiest step. Call the constructor for &lt;code&gt;NSOpenPanel&lt;/code&gt; or &lt;code&gt;NSSavePanel&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; savePanel = NSSavePanel()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;customizingthepanelsappearance&#34;&gt;Customizing the Panel’s Appearance&lt;/h3&gt;&#xA;&lt;p&gt;When you create an open or save panel, you get the default appearance, which works well most of the time. But if you’re using a save panel to export a file, you want the button to say Export instead of Save because you’re exporting a file. AppKit provides several ways to customize the appearance of open and save panels. Some of the most popular ways include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The &lt;code&gt;prompt&lt;/code&gt; property lets you change the text of the default button.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;title&lt;/code&gt; property lets you change the title of the panel.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;nameFieldLabel&lt;/code&gt; property lets you change the label text in front of the filename text field.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;nameFieldStringValue&lt;/code&gt; property lets you set the filename currently shown in the filename text field.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;directoryURL&lt;/code&gt; property lets you set the current directory for the panel.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;accessoryView&lt;/code&gt; property lets you add an accessory view. A common use of an accessory view is to show a popup button with a list of file types.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;allowedFileTypes&lt;/code&gt; property lets you limit the file types you can open or save.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;customappearanceexample&#34;&gt;Custom Appearance Example&lt;/h3&gt;&#xA;&lt;p&gt;As an example, I’m going to share the code for a custom save panel for &lt;a href=&#34;https://www.checksimsoftware.com/bartleby/&#34;&gt;an app I’m developing&lt;/a&gt;. In this project I’m using a save panel to publish an EPUB book.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buildPublishSavePanel&lt;/span&gt;() -&amp;gt; NSSavePanel {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; savePanel = NSSavePanel()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  savePanel.title = &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;“&lt;/span&gt;Publish Book&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;”&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  savePanel.nameFieldLabel = &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;“&lt;/span&gt;Book Name:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;”&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  savePanel.nameFieldStringValue = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.displayName&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  savePanel.prompt = &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;“&lt;/span&gt;Publish&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;”&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  savePanel.allowedFileTypes = [&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;“&lt;/span&gt;epub&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;”&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; savePanel&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because the save panel is for publishing books, I changed the panel’s title, name field label, and prompt (button text) to let people know this panel is for publishing books. I’m publishing EPUB books so I’m limiting the file types to files with the &lt;code&gt;epub&lt;/code&gt; extension.&lt;/p&gt;&#xA;&lt;p&gt;The most confusing line of code is the line that sets the text field value to &lt;code&gt;self.displayName&lt;/code&gt;. The display name is the filename of the document that I’m publishing.&lt;/p&gt;&#xA;&lt;h3 id=&#34;showingthepanel&#34;&gt;Showing the Panel&lt;/h3&gt;&#xA;&lt;p&gt;There are two ways to show an open or save panel. The easiest way is to show a panel as a modeless window. Call the panel’s &lt;code&gt;begin&lt;/code&gt; method and supply a closure.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;savePanel.begin { (result: NSApplication.ModalResponse) -&amp;gt; Void &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Code to come later&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The other way is to show the panel as a sheet inside the document window. Call the panel’s &lt;code&gt;beginSheetModal&lt;/code&gt; method. Supply the window and a closure.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;savePanel.beginSheetModal(for: window) {&#xA;  (result: NSApplication.ModalResponse) -&amp;gt; Void in {&#xA;    // Put your code here&#xA;  }&#xA;}  &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;handlingthedefaultbuttonclick&#34;&gt;Handling the Default Button Click&lt;/h3&gt;&#xA;&lt;p&gt;After showing the panel, you must handle the clicking of the default button (Open for an open panel, Save for a save panel). What you must do is check if the result of the panel running is &lt;code&gt;NSFileHandlingPanelOKButton&lt;/code&gt;, which occurs when someone clicks the default button. Usually you will call a function that performs the task you want to do. For example if you were exporting a file, you would call a function that exports the file.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thefullexample&#34;&gt;The Full Example&lt;/h3&gt;&#xA;&lt;p&gt;The following code shows the full example of using a save panel to publish a book:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;showPublishSavePanel&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; savePanel = buildPublishSavePanel()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  savePanel.begin { (result: NSApplication.ModalResponse) -&amp;gt; Void &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; result.rawValue == NSFileHandlingPanelOKButton {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; panelURL = savePanel.url {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Replace this code with &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// a call to a function you wrote.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        publishEPUB(location: panelURL)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#75715e&#34;&gt;// End of closure&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code begins by calling the &lt;code&gt;buildPublishSavePanel&lt;/code&gt; function I wrote earlier to create the save panel and customize how it looks.&lt;/p&gt;&#xA;&lt;p&gt;The next line of code calls the save panel’s &lt;code&gt;begin&lt;/code&gt; method to show the save panel. The closure in the &lt;code&gt;begin&lt;/code&gt; method uses a variable, &lt;code&gt;result&lt;/code&gt; that stores the result of someone interacting with the save panel.&lt;/p&gt;&#xA;&lt;p&gt;The first &lt;code&gt;if&lt;/code&gt; statement checks if the person clicks the default (Publish) button. If so, the second &lt;code&gt;if&lt;/code&gt; statement runs.&lt;/p&gt;&#xA;&lt;p&gt;The second &lt;code&gt;if&lt;/code&gt; statement gets the URL of the location the person chose to store the published book and calls a function to publish an EPUB book at the supplied URL. In your app you would call a function you wrote that creates (examples: importing or exporting a file) a file at the given URL.&lt;!-- raw HTML omitted --&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Changing the Button Title for Open and Save Panels</title>
      <link>https://swiftdevjournal.com/changing-the-button-title-for-open-and-save-panels/</link>
      <pubDate>Tue, 01 Sep 2020 19:20:49 +0000</pubDate>
      <guid>https://swiftdevjournal.com/changing-the-button-title-for-open-and-save-panels/</guid>
      <description>&lt;p&gt;Open and save panels are how Mac apps let people open and save files. An open panel defaults to using Open as the text for the main button. A save panel defaults to using Save. The default values make sense, but suppose you want to use an open panel to import a file in your app. How do you change the button text from Open to Import?&lt;/p&gt;&#xA;&lt;p&gt;Use the &lt;code&gt;prompt&lt;/code&gt; property to change the button text. The following example shows how to change the button text in an open panel from Open to Import:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buildImportOpenPanel&lt;/span&gt;() -&amp;gt; NSOpenPanel {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; openPanel = NSOpenPanel()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  openPanel.prompt = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Import&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; openPanel&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Look at the &lt;code&gt;NSSavePanel&lt;/code&gt; class reference to see other ways to customize the appearance of save and open panels.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Adding Undo Support for NSTextView</title>
      <link>https://swiftdevjournal.com/adding-undo-support-for-nstextview/</link>
      <pubDate>Mon, 22 Jun 2020 17:31:07 +0000</pubDate>
      <guid>https://swiftdevjournal.com/adding-undo-support-for-nstextview/</guid>
      <description>&lt;p&gt;Mac text views support undo and redo for text editing without you having to write any code. All you have to do is set the text view’s &lt;code&gt;allowsUndo&lt;/code&gt; property to true, which you can set in the attributes inspector.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/NSTextViewAllowUndo.png&#34; alt=&#34;text view allow undo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the Allows Undo checkbox to turn on the text view’s undo/redo support.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Showing a Sheet When Choosing a Menu Item in AppKit</title>
      <link>https://swiftdevjournal.com/showing-a-sheet-when-choosing-a-menu-item/</link>
      <pubDate>Tue, 09 Jun 2020 18:12:08 +0000</pubDate>
      <guid>https://swiftdevjournal.com/showing-a-sheet-when-choosing-a-menu-item/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://www.voodoopad.com&#34;&gt;VoodooPad&lt;/a&gt; is a Mac app for building a personal wiki. When you create a new wiki page in VoodooPad, a sheet opens for you to name the page.&lt;/p&gt;&#xA;&lt;p&gt;I wanted something similar in one of my Mac app projects that uses storyboards. I created a view controller for the sheet. I added a toolbar button, made a connection to the sheet’s view controller and chose Sheet from the list of available storyboard segues.&lt;/p&gt;&#xA;&lt;p&gt;One of Apple’s guidelines for Mac user interfaces is that every toolbar button should have a menu item. So I created a menu item to show the sheet and made a connection from the menu item to the sheet’s view controller. But there was no Sheet segue available. The only available segues were Custom, Show, and Modal. How do you show a sheet after choosing a menu item?&lt;/p&gt;&#xA;&lt;h3 id=&#34;solutionoverview&#34;&gt;Solution Overview&lt;/h3&gt;&#xA;&lt;p&gt;You must perform the following steps to show a sheet from a menu in a Mac app using storyboards:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Give the sheet’s view controller a storyboard ID to identify the view controller.&lt;/li&gt;&#xA;&lt;li&gt;Add an action to the main view controller that creates an instance of the sheet view controller and presents it as a sheet.&lt;/li&gt;&#xA;&lt;li&gt;Connect the menu item to the action.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;givethesheetsviewcontrollerastoryboardid&#34;&gt;Give the Sheet’s View Controller a Storyboard ID&lt;/h3&gt;&#xA;&lt;p&gt;The sheet’s view controller needs a storyboard ID so you can create an instance of the view controller in your code. Select the sheet’s view controller from the storyboard and open the identity inspector.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ViewControllerStoryboardID.png&#34; alt=&#34;view controller storyboard ID&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter the ID in the Storyboard ID text field. Remember the ID because you will need it when writing the code to show the sheet.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addanactiontothemainviewcontrollertoshowthesheet&#34;&gt;Add an Action to the Main View Controller to Show the Sheet&lt;/h3&gt;&#xA;&lt;p&gt;You must write an action in the main view controller to show the sheet. When someone chooses the menu item, your app performs the action. The main view controller is the controller that shows the window’s content.&lt;/p&gt;&#xA;&lt;p&gt;The first step is to get the storyboard where the sheet view controller resides. I’m going to assume the main view controller and sheet view controller reside in the same storyboard so I can use the main view controller’s &lt;code&gt;storyboard&lt;/code&gt; property to get the storyboard.&lt;/p&gt;&#xA;&lt;p&gt;After getting the storyboard, call its &lt;code&gt;instantiateController&lt;/code&gt; method, supplying the sheet view controller’s storyboard ID. After instantiating the sheet view controller, call the &lt;code&gt;presentAsSheet&lt;/code&gt; method, supplying the sheet view controller.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@IBAction&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;showSheet&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; sender: AnyObject) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; theStoryboard = storyboard,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sheetViewController = &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      theStoryboard.instantiateController&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (withIdentifier: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sheetViewControllerID&amp;#34;&lt;/span&gt;) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? MySheetViewController {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    presentAsSheet(sheetViewController)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;connectthemenuitem&#34;&gt;Connect the Menu Item&lt;/h3&gt;&#xA;&lt;p&gt;The last step is to connect the menu item to the action you wrote to show the sheet. Make a connection from the menu item to the First Responder object in the Application scene. A long list of actions opens. Choose the action you created to show the sheet.&lt;/p&gt;&#xA;&lt;p&gt;When someone chooses the menu item, your app will call the action you wrote. Calling the action will show the sheet.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Code Signing and the Sparkle Framework</title>
      <link>https://swiftdevjournal.com/code-signing-and-the-sparkle-framework/</link>
      <pubDate>Wed, 03 Jun 2020 19:14:21 +0000</pubDate>
      <guid>https://swiftdevjournal.com/code-signing-and-the-sparkle-framework/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://sparkle-project.org&#34;&gt;Sparkle&lt;/a&gt; is a framework that simplifies updating Mac apps. With Sparkle people can check for updates inside your app. If there is a new version of your app, they can download and install it from your app.&lt;/p&gt;&#xA;&lt;p&gt;I recently added Sparkle support to &lt;a href=&#34;https://www.checksimsoftware.com/bartleby/&#34;&gt;an app I’m developing&lt;/a&gt;. Sparkle has good setup instructions, but I ran into one issue not covered by their instructions. This article tells the story of me discovering and fixing this issue.&lt;/p&gt;&#xA;&lt;h3 id=&#34;backgroundinformation&#34;&gt;Background Information&lt;/h3&gt;&#xA;&lt;p&gt;Sparkle currently has two branches: a stable version 1 and a beta version 2, which adds support for sandboxed apps. Version 1 has a binary framework and related files that you can download and add to your project. You can also download the Xcode project from GitHub and build the framework yourself. Version 2 must be built from source by downloading the Xcode project.&lt;/p&gt;&#xA;&lt;p&gt;Sparkle supports CocoaPods, but I chose to download the version 1 binary framework and add it to my project. My app isn’t sandboxed so I didn’t need version 2, and version 1 has much more documentation.&lt;/p&gt;&#xA;&lt;h3 id=&#34;theproblem&#34;&gt;The Problem&lt;/h3&gt;&#xA;&lt;p&gt;I followed the &lt;a href=&#34;https://sparkle-project.org/documentation/&#34;&gt;installation instructions on the Sparkle site&lt;/a&gt;. I built and run the app, but it kept crashing at launch. The following error message appeared in Xcode’s debug console for the Sparkle framework:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;not valid for use in process using Library Validation: mapped file has no Team ID and is not a platform binary&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The Team ID is the code signing development team.&lt;/p&gt;&#xA;&lt;h3 id=&#34;initialsearchtofindtheproblem&#34;&gt;Initial Search to Find the Problem&lt;/h3&gt;&#xA;&lt;p&gt;I started my search for a solution by browsing the GitHub issues for the Sparkle project. I did not find any issues similar to the one I found.&lt;/p&gt;&#xA;&lt;p&gt;The next step was to paste the console error message into a search engine. I found a thread in Apple’s paid developer forums where an Apple engineer said you have to code sign the framework with your code signing identity.&lt;/p&gt;&#xA;&lt;p&gt;Yes! Code sign Sparkle with my code signing identity, and the problem will go away.&lt;/p&gt;&#xA;&lt;h3 id=&#34;codesignsparkle&#34;&gt;Code Sign Sparkle&lt;/h3&gt;&#xA;&lt;p&gt;I knew I wouldn’t be able to code sign the Sparkle binary framework. I would have to clone the project in Xcode, change the code signing build settings to use my code signing identity, build the framework, and add it to my project.&lt;/p&gt;&#xA;&lt;p&gt;I wasn’t able to build version 1 from source (compiler errors) but was able to build version 2 so I went with that. I changed the code signing build settings, built the framework, and added it to the project.&lt;/p&gt;&#xA;&lt;p&gt;The app continued to crash at launch with the same error message in the debug console. What was going on?&lt;/p&gt;&#xA;&lt;h3 id=&#34;thesolution&#34;&gt;The Solution&lt;/h3&gt;&#xA;&lt;p&gt;Some more Internet searching for the error message took me to an article on testing a Swift Package Manager package. A sentence in the article, “To avoid signing issue, we need to select a Team for all frameworks”, led me to the solution.&lt;/p&gt;&#xA;&lt;p&gt;I did not need to modify any code signing build settings to fix the issue. I had to change the Signing Certificate value for my app target in the Signing &amp;amp; Capabilities section.&lt;/p&gt;&#xA;&lt;!-- raw HTML omitted --&gt;&#xA;&lt;p&gt;The original Signing Certificate value was Sign to Run Locally. I had to change it to Development.&lt;/p&gt;&#xA;&lt;p&gt;After changing the Signing Certificate value, I was able to use Sparkle in my app. I was able to use both the binary version 1 framework and the version 2 framework I built from the Xcode project. I ended up using the binary version 1 framework.&lt;/p&gt;&#xA;&lt;p&gt;It took me several hours to solve the code signing issue. I hope this article keeps someone else from making the same mistakes I made.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Saving Data in a Swift App</title>
      <link>https://swiftdevjournal.com/saving-data-in-a-swift-app/</link>
      <pubDate>Tue, 12 May 2020 19:07:23 +0000</pubDate>
      <guid>https://swiftdevjournal.com/saving-data-in-a-swift-app/</guid>
      <description>&lt;p&gt;People new to iOS development frequently ask how to save data in their apps. Apple provides the following technologies for saving app data on a local device:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;UserDefaults&lt;/li&gt;&#xA;&lt;li&gt;Keychain&lt;/li&gt;&#xA;&lt;li&gt;Files&lt;/li&gt;&#xA;&lt;li&gt;Core Data&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;You can use multiple methods to save data in your app. Many iOS and Mac apps use both UserDefaults and Core Data to save data. Use all the methods for saving data that make sense for your app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;userdefaults&#34;&gt;UserDefaults&lt;/h3&gt;&#xA;&lt;p&gt;Apple provides a &lt;code&gt;UserDefaults&lt;/code&gt; class that provides a programming interface to your app’s defaults database. The defaults database contains user settings and preferences.&lt;/p&gt;&#xA;&lt;p&gt;Use UserDefaults to store small amounts of data, like settings and preferences. If you are writing a plain text editor, you could store the font to use in UserDefaults.&lt;/p&gt;&#xA;&lt;h3 id=&#34;keychain&#34;&gt;Keychain&lt;/h3&gt;&#xA;&lt;p&gt;Use the keychain to store small amounts of data securely, such as passwords. If you were writing a Twitter app, you could use the keychain to store the person’s Twitter handle and password.&lt;/p&gt;&#xA;&lt;p&gt;Apple provides a Keychain Services API for apps to work with the keychain. The documentation is in the System &amp;gt; Security section of Apple’s documentation in Xcode. Choose Help &amp;gt; Developer Documentation in Xcode to read the documentation.&lt;/p&gt;&#xA;&lt;p&gt;The following article provides an introduction on working with the keychain:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/saving-passwords-in-the-keychain-in-swift/&#34;&gt;Saving Passwords in the Keychain in Swift&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;files&#34;&gt;Files&lt;/h3&gt;&#xA;&lt;p&gt;You can use files to store larger amounts of data. Document-based apps, such as text editors, spreadsheets, and drawing apps, usually save their data in files.&lt;/p&gt;&#xA;&lt;p&gt;Apple provides the &lt;code&gt;Codable&lt;/code&gt; protocol to simplify reading and writing data to files. An Internet search for &lt;strong&gt;Swift Codable tutorial&lt;/strong&gt; yields many results, most of which cover JSON.&lt;/p&gt;&#xA;&lt;h3 id=&#34;coredata&#34;&gt;Core Data&lt;/h3&gt;&#xA;&lt;p&gt;Core Data is Apple’s framework for creating and working with a data model for iOS and Mac apps. One of the things Core Data does is save data for you.&lt;/p&gt;&#xA;&lt;p&gt;Core Data is a huge subject. People have written books about it. You can find an overview of Core Data in Apple’s documentation in Xcode under App Services. Apple also has a &lt;a href=&#34;https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/index.html#//apple_ref/doc/uid/TP40001075&#34;&gt;Core Data Programming Guide&lt;/a&gt; on their developer website.&lt;/p&gt;&#xA;&lt;h3 id=&#34;coredataorfiles&#34;&gt;Core Data or Files?&lt;/h3&gt;&#xA;&lt;p&gt;Should you use Core Data or files to save larger amounts of data?&lt;/p&gt;&#xA;&lt;p&gt;Core Data is a powerful framework that does a lot, much more than saving app data. But with that power comes a learning curve.&lt;/p&gt;&#xA;&lt;p&gt;You must determine if your app’s data needs require Core Data. Avoid Core Data (or at least do some more research before using Core Data) in the following cases:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Your app supports non-Apple platforms like Android, Linux, and Windows. Core Data does not run on non-Apple platforms.&lt;/li&gt;&#xA;&lt;li&gt;Your data can easily be saved in one file.&lt;/li&gt;&#xA;&lt;li&gt;Your app data has only one class or struct.&lt;/li&gt;&#xA;&lt;li&gt;You are writing a document-based app. Core Data supports document-based apps, but it doesn’t add much to Apple’s document architecture.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A text editor is an example of a project where you should save your data in a file. The app data is just a bunch of text. The data can easily be saved in one file. Core Data would not help you much.&lt;/p&gt;&#xA;&lt;p&gt;Use Core Data to save your app’s data in the following cases:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;You store large amounts of data in the app.&lt;/li&gt;&#xA;&lt;li&gt;The data makes more sense to store in a database than in a single file.&lt;/li&gt;&#xA;&lt;li&gt;Your app data has multiple classes or structs.&lt;/li&gt;&#xA;&lt;li&gt;You are writing a shoebox (not document-based) app.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A blog editor is an example of a project where you should use Core Data. A blog can contain hundreds of posts that would be difficult to store in a file. A blog has multiple pieces of data: titles, tags, categories, and authors. Core Data can do things like show you all the blog posts with a given tag. Take advantage of Core Data if it will help for your app.&lt;/p&gt;&#xA;&lt;p&gt;If you are still not sure whether or not to use Core Data, use it.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Scrolling an iOS Text View When the Keyboard Appears</title>
      <link>https://swiftdevjournal.com/scrolling-an-ios-text-view-when-the-keyboard-appears/</link>
      <pubDate>Mon, 04 May 2020 19:08:42 +0000</pubDate>
      <guid>https://swiftdevjournal.com/scrolling-an-ios-text-view-when-the-keyboard-appears/</guid>
      <description>&lt;p&gt;A common issue iOS developers run into is dealing with the onscreen keyboard. The keyboard appears and blocks what you’re typing.&lt;/p&gt;&#xA;&lt;p&gt;The fix is to scroll the text view when the keyboard appears. The code to do this is not too hard. iOS posts a notification when the keyboard appears and when the keyboard disappears. Write a function to handle each notification. Scroll the text view when the keyboard appears and return it to its original position when the keyboard disappears.&lt;/p&gt;&#xA;&lt;h3 id=&#34;handlingthekeyboardappearingnotification&#34;&gt;Handling the Keyboard Appearing Notification&lt;/h3&gt;&#xA;&lt;p&gt;You must write the function &lt;code&gt;keyboardWasShown&lt;/code&gt;. This function gets called when the keyboard appears.&lt;/p&gt;&#xA;&lt;p&gt;There are two things to do in &lt;code&gt;keyboardWasShown&lt;/code&gt; to scroll the text view. First, set the text view’s content inset so the bottom edge is the keyboard’s height. Second, set the scroll indicator insets to the text view’s content inset.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@objc&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;keyboardWasShown&lt;/span&gt;(notification: NSNotification) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; info = notification.userInfo&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; keyboardRect = info?[UIResponder.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    keyboardFrameBeginUserInfoKey] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? CGRect {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; keyboardSize = keyboardRect.size&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#x9;textView.contentInset = UIEdgeInsets(top: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;left&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      bottom: keyboardSize.height, &lt;span style=&#34;color:#66d9ef&#34;&gt;right&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    textView.scrollIndicatorInsets = textView.contentInset&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Swift functions that work with notifications require the &lt;code&gt;@objc&lt;/code&gt; keyword at the start of the function declaration. The &lt;code&gt;userInfo&lt;/code&gt; property of the notification contains the rectangle where the keyboard appears on the screen.&lt;/p&gt;&#xA;&lt;p&gt;Use the keyboard rectangle to get the keyboard’s height. Set the text view’s bottom edge inset to the keyboard’s height. The text view will scroll when the text insertion point gets near the top of the keyboard.&lt;/p&gt;&#xA;&lt;h3 id=&#34;handlingthekeyboardhidingnotification&#34;&gt;Handling the Keyboard Hiding Notification&lt;/h3&gt;&#xA;&lt;p&gt;You must write the function &lt;code&gt;keyboardWillBeHidden&lt;/code&gt;. This function gets called when the person entering text hides the keyboard.&lt;/p&gt;&#xA;&lt;p&gt;When the keyboard disappears, set the text view’s content inset back to all zeroes. Set the text view’s scroll indicator insets to the text view’s content inset.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@objc&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;keyboardWillBeHidden&lt;/span&gt;(notification: NSNotification) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  textView.contentInset = UIEdgeInsets(top: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;left&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bottom: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;right&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  textView.scrollIndicatorInsets = textView.contentInset&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;exampleproject&#34;&gt;Example Project&lt;/h3&gt;&#xA;&lt;p&gt;I have a &lt;a href=&#34;https://github.com/SwiftDevJournal/iOSRichTextEditor&#34;&gt;text editor project on GitHub&lt;/a&gt; to see the keyboard handling code in practice.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Xcode Breakpoint Actions</title>
      <link>https://swiftdevjournal.com/xcode-breakpoint-actions/</link>
      <pubDate>Fri, 24 Apr 2020 19:18:49 +0000</pubDate>
      <guid>https://swiftdevjournal.com/xcode-breakpoint-actions/</guid>
      <description>&lt;p&gt;Xcode’s breakpoints pause your program so you can step through your code line by line and examine the values of your variables. But sometimes you don’t want to pause your program. You want to do something like print the value of a variable to the console. Xcode has breakpoint actions that let you do things like print a variable’s value, run debugger commands, and run scripts.&lt;/p&gt;&#xA;&lt;p&gt;If you’re unfamiliar with Xcode breakpoints, read &lt;a href=&#34;https://www.swiftdevjournal.com/an-introduction-to-xcodes-debugger/&#34;&gt;Introduction to Xcode’s Debugger&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingabreakpointaction&#34;&gt;Creating a Breakpoint Action&lt;/h3&gt;&#xA;&lt;p&gt;Right-click on a breakpoint in Xcode’s editor or in Xcode’s breakpoint navigator (Press Cmd–8) and choose Edit Breakpoint. A popover opens to edit the breakpoint.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeBreakpointEditor.png&#34; alt=&#34;Xcode breakpoint editor&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the Add Action button to create a breakpoint action.&lt;/p&gt;&#xA;&lt;h3 id=&#34;breakpointactions&#34;&gt;Breakpoint Actions&lt;/h3&gt;&#xA;&lt;p&gt;When you click the Add Action button, the popover looks similar to the following screenshot:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeBreakpointActionEditor.png&#34; alt=&#34;Xcode breakpoint action editor&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Xcode provides the following breakpoint actions:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;AppleScript&lt;/li&gt;&#xA;&lt;li&gt;Capture GPU Frame&lt;/li&gt;&#xA;&lt;li&gt;Debugger Command&lt;/li&gt;&#xA;&lt;li&gt;Log Message&lt;/li&gt;&#xA;&lt;li&gt;Shell Command&lt;/li&gt;&#xA;&lt;li&gt;Sound&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A breakpoint can have multiple actions. For example you can run a debugger command and play a sound when reaching a breakpoint.&lt;/p&gt;&#xA;&lt;h4 id=&#34;applescript&#34;&gt;AppleScript&lt;/h4&gt;&#xA;&lt;p&gt;The AppleScript breakpoint action runs an AppleScript script.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeAppleScriptAction.png&#34; alt=&#34;AppleScript action&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter the script text in the text view. Most of you using the AppleScript action will write the script in a text editor and paste it into the text view. Click the Compile button to make sure the script works.&lt;/p&gt;&#xA;&lt;h4 id=&#34;capturegpuframe&#34;&gt;Capture GPU Frame&lt;/h4&gt;&#xA;&lt;p&gt;The Capture GPU Frame action captures a frame from the graphics card. This action helps most with apps that work with graphics, such as games, image editors, and video editing apps.&lt;/p&gt;&#xA;&lt;h4 id=&#34;debuggercommand&#34;&gt;Debugger Command&lt;/h4&gt;&#xA;&lt;p&gt;The Debugger Command action runs an LLDB debugger command. The &lt;a href=&#34;https://lldb.llvm.org/index.html&#34;&gt;LLDB site&lt;/a&gt; has information on all the LLDB commands.&lt;/p&gt;&#xA;&lt;p&gt;Enter the command in the text field.&lt;/p&gt;&#xA;&lt;h4 id=&#34;logmessage&#34;&gt;Log Message&lt;/h4&gt;&#xA;&lt;p&gt;The Log Message breakpoint action logs a message to Xcode’s debug console. A common use of message logging is to write the value of a variable to the console. Use this action as an alternative to littering your code with &lt;code&gt;print&lt;/code&gt; statements for debugging purposes.&lt;/p&gt;&#xA;&lt;p&gt;Most text that you enter in the text field will appear that way in the console. Wrap variable names with the @ character. Suppose you have a game and want to display the player’s x position. The following log message:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Player X: @player.position.x@&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Prints the following in the console if the x position is 12:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Player X: 12&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;shellcommand&#34;&gt;Shell Command&lt;/h4&gt;&#xA;&lt;p&gt;The Shell Command action runs a shell script. You can use this action to run command-line programs as well as shell scripts.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeShellCommandAction.png&#34; alt=&#34;shell command action&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter the command in the top text field, or click the Choose button to locate a shell script on your Mac. Enter any arguments in the bottom text field. Selecting the Wait until done checkbox tells Xcode to wait until the shell script finishes to continue.&lt;/p&gt;&#xA;&lt;h3 id=&#34;sound&#34;&gt;Sound&lt;/h3&gt;&#xA;&lt;p&gt;The Sound action plays a sound. Playing a sound lets you know you hit the breakpoint. Normally you mix the Sound action with other breakpoint actions.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/XcodeSoundAction.png&#34; alt=&#34;sound action&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Choose a sound from the menu.&lt;/p&gt;&#xA;&lt;h3 id=&#34;automaticallycontinue&#34;&gt;Automatically Continue&lt;/h3&gt;&#xA;&lt;p&gt;At the bottom of the breakpoint editor popover is a checkbox to automatically continue after running the breakpoint actions. If you’re using breakpoint actions, you should select the checkbox so you don’t have to click the Resume button to resume running your app.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>It’s OK to Use Storyboards</title>
      <link>https://swiftdevjournal.com/its-ok-to-use-storyboards/</link>
      <pubDate>Tue, 14 Apr 2020 18:57:54 +0000</pubDate>
      <guid>https://swiftdevjournal.com/its-ok-to-use-storyboards/</guid>
      <description>&lt;p&gt;A common question new iOS developers ask is how to build their app’s user interface: code or storyboards. People adamant about building their interfaces in code inevitably join in to say that building interfaces in code is the right way, the way big companies make iOS apps. But it’s OK to use storyboards for your user interface, especially if you are new to iOS development.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatswrongwithstoryboards&#34;&gt;What’s Wrong with Storyboards?&lt;/h3&gt;&#xA;&lt;p&gt;Storyboards have two main issues. The first issue involves version control. If multiple people make changes to a storyboard, commit the changes, and merge the changes, conflicts occur that are difficult to resolve.&lt;/p&gt;&#xA;&lt;p&gt;Merge conflicts are a serious issue, but if you’re a new iOS developer, you probably are working alone. You’re the only one editing the storyboard so you don’t have to worry about merge conflicts.&lt;/p&gt;&#xA;&lt;p&gt;The second issue with storyboards is that editing them can be slow if you jam 10 or more screens into a single storyboard. If you run into this issue, the solution is to use multiple storyboards. Select the view controller scenes you want to put in a new storyboard and choose Edit &amp;gt; Refactor to Storyboard.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whyusestoryboards&#34;&gt;Why Use Storyboards?&lt;/h3&gt;&#xA;&lt;p&gt;The point of this article isn’t to show that storyboards are better than code for building user interfaces, but the following list shows some reasons to use storyboards:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;UIKit is meant to work with storyboards. Xcode projects that use UIKit include a storyboard for a reason.&lt;/li&gt;&#xA;&lt;li&gt;Using storyboards is easier for new iOS developers than building a user interface entirely in code. Dragging a button or other control to a screen is easier than figuring out the code you have to write to create and place that control.&lt;/li&gt;&#xA;&lt;li&gt;Storyboards let you see how your interface looks before running the app. With code you have to build and run the project to see how the interface looks.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;&#xA;&lt;p&gt;Build your user interface however you want. But it’s OK to use storyboards. You’re not doing it wrong if you use a storyboard for your app’s user interface, no matter what someone on Reddit or Slack tells you.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Creating Custom Elements and Attributes in the Plot HTML Framework</title>
      <link>https://swiftdevjournal.com/creating-custom-elements-and-attributes-in-the-plot-html-framework/</link>
      <pubDate>Wed, 08 Apr 2020 19:22:04 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-custom-elements-and-attributes-in-the-plot-html-framework/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/JohnSundell/Plot&#34;&gt;Plot&lt;/a&gt; is a framework for creating HTML and XML documents in Swift. The Plot framework supports the most common HTML elements and attributes. But if you want to do something Plot doesn’t natively support, such as create an EPUB book, you must create custom elements and attributes. In this article I share what I’ve learned about creating custom elements and attributes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;customelements&#34;&gt;Custom Elements&lt;/h3&gt;&#xA;&lt;p&gt;You can think of an element as a tag. Examples of HTML elements include &lt;code&gt;p&lt;/code&gt; for paragraphs, &lt;code&gt;h1&lt;/code&gt; for heading 1, and &lt;code&gt;li&lt;/code&gt; for a list item. Create a custom element if there is an element you need that Plot does not have. You are more likely to create custom elements for XML than HTML.&lt;/p&gt;&#xA;&lt;h3 id=&#34;customattributes&#34;&gt;Custom Attributes&lt;/h3&gt;&#xA;&lt;p&gt;An attribute is a value that appears inside an HTML or XML element. HTML links have a &lt;code&gt;href&lt;/code&gt; attribute with the link destination.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;a href=&amp;#34;https://github.com&amp;#34;&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Like elements, you are more likely to create custom attributes for XML than HTML. Custom elements are likely to require custom attributes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingacustomelement&#34;&gt;Creating a Custom Element&lt;/h3&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;.element&lt;/code&gt; function to create a custom element. There are multiple ways to call the &lt;code&gt;.element&lt;/code&gt; function. A simple way to call it is to supply a text value for the element. The following call:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.element(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;country&amp;#34;&lt;/span&gt;, text: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mexico&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Creates the following XML tag:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;country&amp;gt;Mexico&amp;lt;/country&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You normally write a static function to create a custom element that makes a call to &lt;code&gt;.element&lt;/code&gt;. The following function creates a custom element for a country:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;country&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; location: String) -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .element(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;country&amp;#34;&lt;/span&gt;, text: location)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;supplyingattributes&#34;&gt;Supplying Attributes&lt;/h4&gt;&#xA;&lt;p&gt;Another way to call &lt;code&gt;.element&lt;/code&gt; is to supply a list of attributes. The following call:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.element(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;meta&amp;#34;&lt;/span&gt;, attributes: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[.attribute(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cover&amp;#34;&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;.attribute(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cover.png&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Creates the following tag:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;meta name=&amp;#34;cover&amp;#34; content=&amp;#34;cover.png&amp;#34; /&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;supplyingalistofnodes&#34;&gt;Supplying a List of Nodes&lt;/h4&gt;&#xA;&lt;p&gt;The final way to call &lt;code&gt;.element&lt;/code&gt; is to supply a list of nodes. Supplying a list of nodes helps when creating nested tags. Normally when you have nested tags, the child nodes are nodes of a custom context.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;XML&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyMetadataContext&lt;/span&gt; {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;metadata&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; nodes: Node&amp;lt;XML.MyMetadataContext&amp;gt;...) -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;.element(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;metadata&amp;#34;&lt;/span&gt;, nodes: nodes)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I explain custom contexts later in this article.&lt;/p&gt;&#xA;&lt;p&gt;Another situation to supply a list of nodes is to create a custom element that includes both a text value and attributes. The following function creates a custom modified date element:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;modifiedDate&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; dateString: String) -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .element(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;meta&amp;#34;&lt;/span&gt;, nodes: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [.attribute(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;property&amp;#34;&lt;/span&gt;,  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       value:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dcterms:modified&amp;#34;&lt;/span&gt;), &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .text(dateString)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Calling &lt;code&gt;modifiedDate&lt;/code&gt; creates an element that looks like the following:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;meta property=&amp;#34;dcterms:modified&amp;#34;&amp;gt;2020-04-03&amp;lt;/meta&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The exact value depends on the date string.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingacustomattribute&#34;&gt;Creating a Custom Attribute&lt;/h3&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;.attribute&lt;/code&gt; function to create a custom attribute. Supply the name of the attribute and its value. The following call:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.attribute(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xml:lang&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;en&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Creates the following attribute:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;xml:lang=&amp;#34;en&amp;#34;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Like with custom elements, you normally write a static function to create a custom attribute. The following function creates a custom attribute for the language of an XML document:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlLang&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; language: String) -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .attribute(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xml:lang&amp;#34;&lt;/span&gt;, value: language)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;example:createaspineforanepubbook&#34;&gt;Example: Create a Spine for an EPUB Book&lt;/h3&gt;&#xA;&lt;p&gt;Now it’s time for a real example, creating the spine for an EPUB book. The spine contains a list of files in the order they appear in the book. The following code shows the XML of a sample spine:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;spine toc=&amp;#34;ncx&amp;#34;&amp;gt;&#xA;  &amp;lt;itemref idref=&amp;#34;Chapter1&amp;#34;/&amp;gt;&#xA;  &amp;lt;itemref idref=&amp;#34;Chapter2&amp;#34;/&amp;gt;&#xA;  &amp;lt;itemref idref=&amp;#34;Chapter3&amp;#34;/&amp;gt;&#xA;  &amp;lt;itemref idref=&amp;#34;Chapter4&amp;#34;/&amp;gt;&#xA;  &amp;lt;itemref idref=&amp;#34;Chapter5&amp;#34;/&amp;gt;&#xA;&amp;lt;/spine&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Building the spine in Plot requires two custom elements: one for the spine and one for the item references. The spine element requires a custom attribute for the table of contents (toc). The item reference element requires a custom attribute for the ID reference.&lt;/p&gt;&#xA;&lt;h4 id=&#34;createnewcontexts&#34;&gt;Create New Contexts&lt;/h4&gt;&#xA;&lt;p&gt;A context is a section of an HTML or XML document where elements and attributes reside. Plot has a &lt;code&gt;BodyContext&lt;/code&gt; for HTML documents that corresponds to the &lt;code&gt;body&lt;/code&gt; tag in the document. Most HTML elements reside in the body context.&lt;/p&gt;&#xA;&lt;p&gt;Custom attributes usually require you to create a custom context. Sometimes custom elements also require a custom context.&lt;/p&gt;&#xA;&lt;p&gt;To create the spine, create new XML contexts for the spine and spine item.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;XML&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SpineContext&lt;/span&gt; {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SpineItemContext&lt;/span&gt; {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;SpineContext&lt;/code&gt; context contains anything inside a &lt;code&gt;spine&lt;/code&gt; tag, which is going to be the spine items and the spine element’s custom attribute. The &lt;code&gt;SpineItemContext&lt;/code&gt; context contains anything inside an &lt;code&gt;itemref&lt;/code&gt; tag, which is each item’s ID reference.&lt;/p&gt;&#xA;&lt;h4 id=&#34;createthespinecustomelement&#34;&gt;Create the Spine Custom Element&lt;/h4&gt;&#xA;&lt;p&gt;The next step is to create the spine custom element, which you can see in the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Node&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; Context == XML.DocumentContext {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;spine&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; nodes: Node&amp;lt;XML.SpineContext&amp;gt;...) -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .element(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;spine&amp;#34;&lt;/span&gt;, nodes: nodes)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code creates an element named &lt;code&gt;spine&lt;/code&gt; with a list of child nodes. The child nodes include the spine’s custom attributes and the item reference elements. The child nodes must be in the spine context.&lt;/p&gt;&#xA;&lt;h4 id=&#34;createthespinecustomattribute&#34;&gt;Create the Spine Custom Attribute&lt;/h4&gt;&#xA;&lt;p&gt;Now let’s create the spine’s custom attribute, which you can see in the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Node&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; Context == XML.SpineContext {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;spineTOC&lt;/span&gt;() -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .attribute(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;toc&amp;#34;&lt;/span&gt;, value: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ncx&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice the class extension for the &lt;code&gt;spineTOC&lt;/code&gt; function applies to the spine context so the attribute appears inside the spine tag.&lt;/p&gt;&#xA;&lt;h4 id=&#34;createtheitemreferenceelement&#34;&gt;Create the Item Reference Element&lt;/h4&gt;&#xA;&lt;p&gt;The next task is to write the code to create the item reference element.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Node&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; Context == XML.SpineContext {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;item&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; nodes: Node&amp;lt;XML.SpineItemContext&amp;gt;...) -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .element(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;itemref&amp;#34;&lt;/span&gt;, nodes: nodes)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;item&lt;/code&gt; function must be inside the spine context for the item reference elements to appear inside the spine tag.&lt;/p&gt;&#xA;&lt;p&gt;The nodes are going to be the ID references.&lt;/p&gt;&#xA;&lt;h4 id=&#34;createtheidreferenceattribute&#34;&gt;Create the ID Reference Attribute&lt;/h4&gt;&#xA;&lt;p&gt;There’s one more custom attribute to write, the item’s ID reference.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Node&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; Context == XML.SpineItemContext {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;itemID&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; name: String) -&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Self&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .attribute(named: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;idref&amp;#34;&lt;/span&gt;, value: name)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;itemID&lt;/code&gt; function must be inside the spine item context for the attributes to appear inside the item reference tag.&lt;/p&gt;&#xA;&lt;h4 id=&#34;creatingthespine&#34;&gt;Creating the Spine&lt;/h4&gt;&#xA;&lt;p&gt;The last step is to write a function to build the spine using the custom elements and attributes. Assume there is a &lt;code&gt;Book&lt;/code&gt; struct that contains a list of chapters. Each chapter has a title.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buildSpine&lt;/span&gt;() -&amp;gt; Node&amp;lt;XML.DocumentContext&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; spine = Node.spine(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .spineTOC(),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .forEach(chapters) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .item(Node.itemID($0.title))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; spine&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first line of code in the &lt;code&gt;buildSpine&lt;/code&gt; function creates the spine custom element. The second line creates the spine element’s custom attribute.&lt;/p&gt;&#xA;&lt;p&gt;For each chapter in the book, the code creates a spine item custom element and an item ID (idref) custom attribute for the spine item. The item ID’s value is the chapter’s title.&lt;/p&gt;&#xA;&lt;p&gt;Once you do the work of writing functions for the custom elements and attributes, it doesn’t take much code to do something like build the spine for an EPUB book.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Submitting Bug Reports to Apple</title>
      <link>https://swiftdevjournal.com/submitting-bug-reports-to-apple/</link>
      <pubDate>Fri, 03 Apr 2020 19:06:51 +0000</pubDate>
      <guid>https://swiftdevjournal.com/submitting-bug-reports-to-apple/</guid>
      <description>&lt;p&gt;If you find a bug or want to request a new feature in Xcode or one of Apple’s frameworks, you can submit a bug report using Xcode’s Help menu. Choose Help &amp;gt; Report an Issue to access Apple’s Feedback Assistant site.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>5 Tips to Get Help Faster Online</title>
      <link>https://swiftdevjournal.com/5-tips-to-get-help-faster-online/</link>
      <pubDate>Wed, 01 Apr 2020 18:58:39 +0000</pubDate>
      <guid>https://swiftdevjournal.com/5-tips-to-get-help-faster-online/</guid>
      <description>&lt;p&gt;When you run into problems developing an iOS or Mac app, you can get help by asking a question online at sites like Stack Overflow, Reddit, Slack, and Apple’s developer forums. If you need to ask a question, use the tips in this article to get answers faster.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tip1:searchfirst&#34;&gt;Tip 1: Search First&lt;/h3&gt;&#xA;&lt;p&gt;The fastest way to get an answer to a question online is to not have to ask it. Before you ask a question, search the site or do a search in a search engine to see if someone else had the same question. The chances are pretty good that someone had the same question and received an answer.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tip2:useadescriptivetitlesubject&#34;&gt;Tip 2: Use a Descriptive Title/Subject&lt;/h3&gt;&#xA;&lt;p&gt;I’m amazed by the number of programming questions I see online with the title “Help”. Just about everyone asking a question on a forum is looking for help. Post a brief summary of the issue in the title that is clear enough that people have a general idea of the problem you’re having.&lt;/p&gt;&#xA;&lt;p&gt;Examples of poor question titles:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Xcode doesn’t work&lt;/li&gt;&#xA;&lt;li&gt;Source code&lt;/li&gt;&#xA;&lt;li&gt;Keyword&lt;/li&gt;&#xA;&lt;li&gt;Crash&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Those titles are too vague. People are less likely to read a poorly titled question. If they don’t read your question, they won’t answer it.&lt;/p&gt;&#xA;&lt;p&gt;Examples of good question titles:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;How do I download Xcode outside the Mac App Store?&lt;/li&gt;&#xA;&lt;li&gt;Using NSArrayController in multiple storyboard scenes&lt;/li&gt;&#xA;&lt;li&gt;UITextView not scrolling in portrait orientation on iOS 11&lt;/li&gt;&#xA;&lt;li&gt;How can I sort a Swift set in alphabetical order?&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;With titles like these someone can tell if the question is worth reading. Poorly titled questions aren’t worth reading.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tip3:dontpostscreenshotsoferrormessagesandcode&#34;&gt;Tip 3: Don’t Post Screenshots of Error Messages and Code&lt;/h3&gt;&#xA;&lt;p&gt;On Reddit and Slack people like to ask a question and show a screenshot of Xcode on their computer. Text in screenshots is difficult to read. In the best case scenario, people will ask for more information, delaying you receiving an answer. In the worst case scenario people will ignore your question.&lt;/p&gt;&#xA;&lt;p&gt;If you are going to include a code listing or error message in your question, paste the code/error message into the question as text.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tip4:postrelevantinformation&#34;&gt;Tip 4: Post Relevant Information&lt;/h3&gt;&#xA;&lt;p&gt;The biggest mistake I see people make when asking programming questions online is not supplying enough information to answer the question. People have to ask for additional information, which delays you getting an answer. To get an answer faster, supply all the information that people need to answer your question.&lt;/p&gt;&#xA;&lt;p&gt;What information is relevant depends on the question, but examples of relevant information include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;What you are trying to accomplish.&lt;/li&gt;&#xA;&lt;li&gt;What you tried.&lt;/li&gt;&#xA;&lt;li&gt;What the specific problem is.&lt;/li&gt;&#xA;&lt;li&gt;The steps to take to reproduce the issue.&lt;/li&gt;&#xA;&lt;li&gt;If you are following a tutorial, provide a link to the tutorial.&lt;/li&gt;&#xA;&lt;li&gt;The code where the problem occurs, if the question is about code.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Remember to be specific with the information you provide. Saying something like “it doesn’t work” can mean many things. It can mean the project doesn’t compile. It can mean the app crashes. It can mean the app does something you don’t expect.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tip5:dontshowallthecodeinyourproject&#34;&gt;Tip 5: Don’t Show All the Code in Your Project&lt;/h3&gt;&#xA;&lt;p&gt;Sometimes people go too far the other way with code listings. They share all the code from their project.&lt;/p&gt;&#xA;&lt;p&gt;People who answer questions online don’t want to read hundreds of lines of code. Post only as much code as you need to show the problem.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Create a Mac Markdown Editor with Live Preview</title>
      <link>https://swiftdevjournal.com/create-a-mac-markdown-editor-with-live-preview/</link>
      <pubDate>Wed, 19 Feb 2020 22:41:49 +0000</pubDate>
      <guid>https://swiftdevjournal.com/create-a-mac-markdown-editor-with-live-preview/</guid>
      <description>&lt;p&gt;I’m working on a Mac app that previews HTML in a web view, and it gave me a good idea for a tutorial. Create a simple Markdown editor with live preview.&lt;/p&gt;&#xA;&lt;p&gt;I &lt;a href=&#34;https://github.com/SwiftDevJournal/MarkdownEditor&#34;&gt;have the project on GitHub&lt;/a&gt; for you to download.&lt;/p&gt;&#xA;&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;&#xA;&lt;p&gt;To take full advantage of this tutorial, you must be running Xcode 11 or later. I use the Swift Package Manager support added in Xcode 11 to add the Ink parser to the project. It might be possible to build a framework for Ink by cloning &lt;a href=&#34;https://github.com/JohnSundell/Ink&#34;&gt;the GitHub project&lt;/a&gt;, but I have not tried it. You could also try searching GitHub for another Markdown parser that supports earlier Xcode versions.&lt;/p&gt;&#xA;&lt;p&gt;I recommend reading the &lt;a href=&#34;https://www.swiftdevjournal.com/create-a-document-based-mac-app-in-swift/&#34;&gt;Create a Document-Based Mac App in Swift article&lt;/a&gt;. It provides an introduction to creating document-based Mac apps and covers some topics that I gloss over in this tutorial. It also has links to other introductory Mac development articles. This tutorial is long enough. If I were to add explanations on basic topics like making connections in storyboards, the tutorial would be as long as a short book.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createtheproject&#34;&gt;Create the Project&lt;/h3&gt;&#xA;&lt;p&gt;Create a Cocoa App project in Xcode. Choose Storyboards from the User Interface menu because this project does not use SwiftUI. Select the Create Document-Based Application checkbox. Enter &lt;code&gt;md&lt;/code&gt; for the document extension, which is the file extension for Markdown documents.&lt;/p&gt;&#xA;&lt;h3 id=&#34;dealwiththeappsandbox&#34;&gt;Deal with the App Sandbox&lt;/h3&gt;&#xA;&lt;p&gt;When I created this project I could not get the live preview to display any HTML. The issue involved the App Sandbox. New Xcode projects use the App Sandbox, which disables all network connections by default.&lt;/p&gt;&#xA;&lt;p&gt;There are two ways to work around the App Sandbox. You can turn off the App Sandbox or turn on network connections by selecting the two Network checkboxes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AppSandboxNetworkConnections.png&#34; alt=&#34;app sandbox network connections&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;importtheinkparser&#34;&gt;Import the Ink Parser&lt;/h3&gt;&#xA;&lt;p&gt;This article uses &lt;a href=&#34;https://github.com/JohnSundell/Ink&#34;&gt;John Sundell’s Ink Markdown parser&lt;/a&gt; to convert Markdown to HTML. Add the Ink parser to the list of Swift packages.&lt;/p&gt;&#xA;&lt;p&gt;Select the project from the project navigator to open the project editor. Select the project file in the project editor. Click the Swift Packages button at the top of the project editor to see a list of installed Swift packages. Click the Add button to add a Swift package.&lt;/p&gt;&#xA;&lt;p&gt;Enter &lt;code&gt;Ink&lt;/code&gt; in the search field and press the Return key to see a list of Swift package repositories with Ink in the name.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ChooseInkParser.png&#34; alt=&#34;choose Ink parser&#34;&gt;&#xA;&lt;!-- raw HTML omitted --&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the Ink item whose owner is JohnSundell. Click the Next button.&lt;/p&gt;&#xA;&lt;p&gt;Now you must determine which version of the Ink parser to use. Click the Branch radio button and enter &lt;code&gt;master&lt;/code&gt;. This tells Xcode to use the most recent stable version of the Ink parser.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SwiftPackageManagerRules.png&#34; alt=&#34;Swift package manager rules&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the Next button to finish adding the Ink parser Swift package to the project.&lt;/p&gt;&#xA;&lt;h3 id=&#34;buildtheuserinterface&#34;&gt;Build the User Interface&lt;/h3&gt;&#xA;&lt;p&gt;The user interface for the Markdown editor consists of a vertical split view with two items. The left view is a plain text text view where you enter Markdown text. The right view is a web view that shows the HTML version of the Markdown text.&lt;/p&gt;&#xA;&lt;p&gt;Open the storyboard. You will see a window with a view controller. Delete that view controller. Add a vertical split view controller to the storyboard. Make the split view controller the window’s content controller by making a connection from the Window Controller item in the window controller scene to the split view controller and selecting the window content relationship segue.&lt;/p&gt;&#xA;&lt;p&gt;Adding the split view controller creates view controller scenes for the two items in the split view. Remove the views in the two view controllers. Add a Plain Document Content Text View item to the first view controller. Add a WebKit View item to the second view controller.&lt;/p&gt;&#xA;&lt;p&gt;Select the text view’s scroll view, open the size inspector, and click the two arrows in the inner autoresizing square. Select the web view and do the same thing. The text view and web view will now resize properly when the window resizes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;setthetextviewsdelegate&#34;&gt;Set the Text View’s Delegate&lt;/h3&gt;&#xA;&lt;p&gt;Set the text view’s delegate to the text view controller so the text view controller will get notified when the text view’s contents change.&lt;/p&gt;&#xA;&lt;p&gt;Make a connection from the text view to the text view controller in the storyboard to set the delegate.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createviewcontrollersubclasses&#34;&gt;Create View Controller Subclasses&lt;/h3&gt;&#xA;&lt;p&gt;The next step is to create Swift files for the three view controllers you created in the storyboard: split view controller, text view controller, and web view controller. I use the name preview view controller for the web view controller.&lt;/p&gt;&#xA;&lt;p&gt;Choose File &amp;gt; New &amp;gt; File to add a new file to the project. Select Cocoa Class from the list of Mac file templates. Enter the name of the class. For the subclass enter &lt;code&gt;NSSplitViewController&lt;/code&gt; for the split view controller and &lt;code&gt;NSViewController&lt;/code&gt; for the other two view controllers. Do not create xib files for the view controllers. You created the view controllers in the storyboard.&lt;/p&gt;&#xA;&lt;p&gt;The text view controller must conform to the &lt;code&gt;NSTextDelegate&lt;/code&gt; protocol to receive any text view notifications, such as the text view contents changing.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TextViewController&lt;/span&gt;: NSViewController, NSTextDelegate {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Open the storyboard and the identity inspector. Set the custom class for each view controller to the subclass you created.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createoutlets&#34;&gt;Create Outlets&lt;/h3&gt;&#xA;&lt;p&gt;The text view controller needs an outlet to access the text view. The preview view controller needs an outlet to access the web view.&lt;/p&gt;&#xA;&lt;p&gt;Open the storyboard and the view controller source file in separate editors. Make a connection from the view in the storyboard to the class in the source code file to create and connect an outlet.&lt;/p&gt;&#xA;&lt;h3 id=&#34;accessingthedocument&#34;&gt;Accessing the Document&lt;/h3&gt;&#xA;&lt;p&gt;The view controllers need access to the document to access and change its contents. The split view controller has access to the document so you can get the document from the split view controller. Add the following function to the split view controller:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getDocument&lt;/span&gt;() -&amp;gt; Document? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; window = view.window,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; windowController = window.windowController {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; windowController.document &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? Document&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Reaching the document requires some deep navigation. You have to get the view, get the view’s window, and get the window’s window controller to access the document.&lt;/p&gt;&#xA;&lt;h3 id=&#34;accessingtheotherviewcontrollers&#34;&gt;Accessing the Other View Controllers&lt;/h3&gt;&#xA;&lt;p&gt;An annoying aspect of Mac split view controllers is they have no easy way for the child view controllers to communicate with each other, even though they’re grouped together in the split view. Each view controller scene is self-contained. For the Markdown editor the text view controller knows nothing about the web view. The web view controller knows nothing about the text view. The view controllers have to go through the split view controller to access the other view controllers.&lt;/p&gt;&#xA;&lt;p&gt;The split view controller has a &lt;code&gt;children&lt;/code&gt; property that contains a list of child view controllers. The text view controller is the first child.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getTextViewController&lt;/span&gt;() -&amp;gt; TextViewController? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; viewController = children.first &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? TextViewController {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; viewController&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The preview view controller is the second child.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getPreviewViewController&lt;/span&gt;() -&amp;gt; PreviewViewController? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; viewController = children[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? PreviewViewController {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; viewController&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add those two functions to the split view controller.&lt;/p&gt;&#xA;&lt;h3 id=&#34;codingthelivepreview&#34;&gt;Coding the Live Preview&lt;/h3&gt;&#xA;&lt;p&gt;When the text changes, you must convert the Markdown to HTML and display it in the web view. Start by importing the Ink framework in the preview view controller.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Ink&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To convert the Markdown to HTML in Ink, create a &lt;code&gt;MarkdownParser&lt;/code&gt; object and call its &lt;code&gt;html&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;parse&lt;/span&gt;(text: String) -&amp;gt; String {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; parser = MarkdownParser()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; parser.html(from: text)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To display the HTML in the web view, call the web view’s &lt;code&gt;loadHTMLString&lt;/code&gt; function. Supply the HTML string as an argument. You can also supply a base URL for relative paths, which can help if you’re going to display images.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updatePreview&lt;/span&gt;(text: String) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; html = parse(text: text)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  previewView.loadHTMLString(html, baseURL: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the &lt;code&gt;parse&lt;/code&gt; and &lt;code&gt;updatePreview&lt;/code&gt; functions to the preview view controller.&lt;/p&gt;&#xA;&lt;h3 id=&#34;tellingthewebviewtoupdate&#34;&gt;Telling the Web View to Update&lt;/h3&gt;&#xA;&lt;p&gt;Call the preview view controller’s &lt;code&gt;updatePreview&lt;/code&gt; function to update the web view. Add the following function to the text view controller:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateLivePreview&lt;/span&gt;(text: String) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; splitViewController = parent &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? SplitViewController,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; previewController = &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      splitViewController.getPreviewViewController() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    previewController.updatePreview(text: text)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice how the text view controller has to go through the split view controller to access the preview view controller to update the preview.&lt;/p&gt;&#xA;&lt;p&gt;Call &lt;code&gt;updateLivePreview&lt;/code&gt; when the text view’s contents change. Add the following function to the text view controller:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;textDidChange&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; notification: Notification) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  updateLivePreview(text: textView.string)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run the project now. You should be able to type in the text view and see the HTML in the web view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;updatingthedocumentcontents&#34;&gt;Updating the Document Contents&lt;/h3&gt;&#xA;&lt;p&gt;When the text view’s contents change, the document’s contents should also change. Start by adding the following property to the &lt;code&gt;Document&lt;/code&gt; class:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; markdown = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;markdown&lt;/code&gt; property stores the document’s contents.&lt;/p&gt;&#xA;&lt;p&gt;Add the following functions to the text view controller:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;saveTextViewContents&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; document = getDocument() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    document.markdown = textView.string&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getDocument&lt;/span&gt;() -&amp;gt; Document? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; splitViewController = parent &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? SplitViewController {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; splitViewController.getDocument()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;saveTextViewContents&lt;/code&gt; function sets the document’s contents to the text view’s contents. The &lt;code&gt;getDocument&lt;/code&gt; function is a helper function to give the text view controller access to the document.&lt;/p&gt;&#xA;&lt;p&gt;Add a call to &lt;code&gt;saveTextViewContents&lt;/code&gt; to the &lt;code&gt;textDidChange&lt;/code&gt; function. Now the document’s contents update when the text view’s contents change.&lt;/p&gt;&#xA;&lt;h3 id=&#34;markingthedocumentaschanged&#34;&gt;Marking the Document as Changed&lt;/h3&gt;&#xA;&lt;p&gt;When someone types in the text view, you must mark the document as being edited so it will autosave. Add the following code to the &lt;code&gt;textDidChange&lt;/code&gt; function:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; document = getDocument() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  document.updateChangeCount(NSDocument.ChangeType.changeDone)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;savingthedocument&#34;&gt;Saving the Document&lt;/h3&gt;&#xA;&lt;p&gt;Open the &lt;code&gt;Document.swift&lt;/code&gt; file. Change the &lt;code&gt;data&lt;/code&gt; function to the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;(ofType typeName: String) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; Data {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; markdown.data(using: .utf8) ?? Data()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code takes the Markdown string and converts it to a &lt;code&gt;Data&lt;/code&gt; object that can be saved to a file. If the conversion fails, save an empty file.&lt;/p&gt;&#xA;&lt;h3 id=&#34;loadingthedocument&#34;&gt;Loading the Document&lt;/h3&gt;&#xA;&lt;p&gt;Open the &lt;code&gt;Document.swift&lt;/code&gt; file. Change the &lt;code&gt;read&lt;/code&gt; function to the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(from data: Data, ofType typeName: String) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fileContents = String(data: data,encoding: .utf8) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    markdown = fileContents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code takes the &lt;code&gt;Data&lt;/code&gt; object from the saved document and converts it to a Swift string. If there is saved text, set the document’s contents to the saved text.&lt;/p&gt;&#xA;&lt;h3 id=&#34;fillthetextviewwhenopeningadocument&#34;&gt;Fill the Text View When Opening a Document&lt;/h3&gt;&#xA;&lt;p&gt;The last step is to fill the text view with the document’s contents when you open a document. Override the &lt;code&gt;viewDidAppear&lt;/code&gt; function in the text view controller and set the text view’s contents to the document’s contents.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;viewDidAppear&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; document = getDocument() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    textView.string = document.markdown&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    updateLivePreview(text: textView.string)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While you’re setting the text view contents you should also update the web view so it shows the HTML preview. That’s why there’s a call to &lt;code&gt;updateLivePreview&lt;/code&gt;. If you didn’t have the call, the preview would be blank until you typed in the text view.&lt;/p&gt;&#xA;&lt;p&gt;Now when you run the project you should have a basic Markdown editor. You can create documents, preview the HTML contents, save documents, and open documents.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Cherry Picking a Git Commit in Xcode</title>
      <link>https://swiftdevjournal.com/cherry-picking-a-git-commit-in-xcode/</link>
      <pubDate>Fri, 07 Feb 2020 17:46:28 +0000</pubDate>
      <guid>https://swiftdevjournal.com/cherry-picking-a-git-commit-in-xcode/</guid>
      <description>&lt;p&gt;Xcode 11 adds support for cherry picking commits. Cherry picking involves taking a commit from one git branch and applying it to another branch. Cherry picking lets you apply a commit to a branch without having to merge all your recent commits into that branch.&lt;/p&gt;&#xA;&lt;p&gt;Take the following steps to cherry pick a commit in Xcode.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Open the source control navigator by pressing Cmd–2.&lt;/li&gt;&#xA;&lt;li&gt;Checkout the destination branch, the branch that will receive the cherry picked commit.&lt;/li&gt;&#xA;&lt;li&gt;Select the branch with the commit to cherry pick. Xcode’s editor will show all the commits for that branch.&lt;/li&gt;&#xA;&lt;li&gt;Select the commit.&lt;/li&gt;&#xA;&lt;li&gt;Right-click and choose Cherry-Pick.&lt;/li&gt;&#xA;&lt;li&gt;An alert will open asking if you want to cherry pick. Click the Cherry-Pick button.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;wanttolearnmoreaboutversioncontrol&#34;&gt;Want to Learn More About Git?&lt;/h3&gt;&#xA;&lt;p&gt;Check out my &lt;a href=&#34;https://www.swiftdevjournal.com/version-control-book/&#34;&gt;version control book&lt;/a&gt;. It shows you how to do the most common git tasks without leaving Xcode. Some of the material covered in the book includes seeing the changes you made to your code, branching, and going back to earlier versions of your project.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Creating Document-Based Apps with SwiftUI</title>
      <link>https://swiftdevjournal.com/creating-document-based-apps-with-swiftui/</link>
      <pubDate>Mon, 06 Jan 2020 20:00:08 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-document-based-apps-with-swiftui/</guid>
      <description>&lt;h4 id=&#34;xcode12notefromtheauthor&#34;&gt;Xcode 12 Note from the Author&lt;/h4&gt;&#xA;&lt;p&gt;Xcode 12 made a bunch of changes to SwiftUI for document-based apps. If you choose a multi-platform document app project, you will get the text editor project I create in this article without having to write any code. I’m keeping this article up for people who are still using Xcode 11.&lt;/p&gt;&#xA;&lt;p&gt;The article &lt;a href=&#34;https://www.swiftdevjournal.com/make-a-markdown-editor-in-swiftui/&#34;&gt;Make a Markdown Editor in SwiftUI&lt;/a&gt; shows how to create a document-based SwiftUI app with Xcode 12.&lt;/p&gt;&#xA;&lt;h4 id=&#34;startoforiginalarticle&#34;&gt;Start of Original Article&lt;/h4&gt;&#xA;&lt;p&gt;I have not seen any articles or tutorials on creating a document-based app with SwiftUI so I’m writing one. In this tutorial you will build an iOS plain text editor.&lt;/p&gt;&#xA;&lt;p&gt;If you haven’t already, I recommend reading two articles before going through the tutorial. &lt;a href=&#34;https://www.swiftdevjournal.com/creating-document-based-ios-apps-part-1/&#34;&gt;Creating Document-Based iOS Apps Part 1&lt;/a&gt; provides an overview of creating document-based iOS apps. &lt;a href=&#34;https://www.swiftdevjournal.com/using-text-views-in-a-swiftui-app/&#34;&gt;Using Text Views in a SwiftUI App&lt;/a&gt; provides an explanation of using a UIKit text view in a SwiftUI app. SwiftUI does not currently have a built-in text view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createtheproject&#34;&gt;Create the Project&lt;/h3&gt;&#xA;&lt;p&gt;Start by creating a project. Create an iOS document-based app project. Choose SwiftUI from the User Interface menu if it’s not already selected.&lt;/p&gt;&#xA;&lt;p&gt;The most interesting files Xcode creates for a document-based SwiftUI app are the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;DocumentBrowserViewController.swift&lt;/code&gt; contains code for the document browser, where people create and open documents.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;DocumentView.Swift&lt;/code&gt; contains code for the document’s main view.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Document.Swift&lt;/code&gt; contains code for the document.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;creatinganewdocument&#34;&gt;Creating a New Document&lt;/h3&gt;&#xA;&lt;p&gt;If you run the project, you’ll notice that tapping the Create Document button does nothing. You must write some code to create the document when someone taps the button. The easiest way to create a new document is to add an empty file to the project. The empty file should have the same file extension as the document’s. This file will be copied to the app bundle when building the project. You’ll have to write some code to load the file from the app bundle.&lt;/p&gt;&#xA;&lt;p&gt;One last thing to do to create documents properly is to configure the document type in Xcode so that the app is an editor of plain text files.&lt;/p&gt;&#xA;&lt;h4 id=&#34;addanemptydocumentfile&#34;&gt;Add an Empty Document File&lt;/h4&gt;&#xA;&lt;p&gt;Choose File &amp;gt; New &amp;gt; File to add a new file to the project. Select Empty from the list of iOS file templates. The empty file is in the Other section. You have to scroll down a bit to reach the Other section.&lt;/p&gt;&#xA;&lt;p&gt;Name the file. I named the file &lt;code&gt;New Document.txt&lt;/code&gt;. You can choose a different name, but remember the name.&lt;/p&gt;&#xA;&lt;h4 id=&#34;loadtheemptydocument&#34;&gt;Load the Empty Document&lt;/h4&gt;&#xA;&lt;p&gt;Open the &lt;code&gt;DocumentBrowserViewController.swift&lt;/code&gt; file and go to the &lt;code&gt;didRequestDocumentCreationWithHandler&lt;/code&gt; function. Replace the following line of code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; newDocumentURL: URL? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; newDocumentURL: URL? = Bundle.main.url(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  forResource: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;New Document&amp;#34;&lt;/span&gt;, withExtension: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;txt&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code loads the empty document file from the app bundle and uses that as the base for a new document.&lt;/p&gt;&#xA;&lt;p&gt;There is one more piece of code to change. In the same function, find the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; newDocumentURL &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  importHandler(newDocumentURL, .move)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  importHandler(&lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, .&lt;span style=&#34;color:#66d9ef&#34;&gt;none&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is a problem with the code inside the &lt;code&gt;if&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;importHandler(newDocumentURL, .move)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This line of code moves the file from the application bundle. Your app will crash the second time you create a document because the empty document file was moved out of the application bundle. The fix is to copy the file from the application bundle when creating a new document.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;importHandler(newDocumentURL, .copy)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;editthedocumenttype&#34;&gt;Edit the Document Type&lt;/h4&gt;&#xA;&lt;p&gt;Xcode initially sets the document type for an iOS document-based app to be a viewer of image files. You must configure the document type in Xcode so that the app is an editor of plain text files. You’re making a text editor, not a text viewer.&lt;/p&gt;&#xA;&lt;p&gt;Select the project from the project navigator to open the project editor. Select the app target from the left side of the project editor. Click the Info button at the top of the project editor to access the document types. Click the disclosure triangle next to Document Types.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DocumentTypes.png&#34; alt=&#34;document types&#34;&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Enter &lt;code&gt;PlainText&lt;/code&gt; in the Name text field.&lt;/li&gt;&#xA;&lt;li&gt;Enter &lt;code&gt;public.plain-text&lt;/code&gt; in the Types text field. &lt;code&gt;public.plain-text&lt;/code&gt; is the UTI (Uniform Type Identifier) for plain text files.&lt;/li&gt;&#xA;&lt;li&gt;In the Additional document type properties section, set the CFBundleTypeRole value to &lt;code&gt;Editor&lt;/code&gt; so people can edit documents.&lt;/li&gt;&#xA;&lt;li&gt;Set the LSHandlerRank value to &lt;code&gt;Alternate&lt;/code&gt; to ensure this text editor isn’t the default text editor for all plain text files.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;createthedatamodel&#34;&gt;Create the Data Model&lt;/h3&gt;&#xA;&lt;p&gt;The data model for this project is simple. The document is the data model. All you have to do is add a property to store the text. Open the &lt;code&gt;Document.swift&lt;/code&gt; file and add the following code inside the &lt;code&gt;Document&lt;/code&gt; class:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code declares a property to store the text and has the initial value of an empty string.&lt;/p&gt;&#xA;&lt;h3 id=&#34;buildingthetextview&#34;&gt;Building the Text View&lt;/h3&gt;&#xA;&lt;p&gt;Now it’s time to add the text view so people can edit text. Currently SwiftUI does not include a text view so you have to write code to create a UIKit text view. But it’s not too much code. Add a new Swift file to your project for the text view. Import the SwiftUI and UIKit frameworks. Add the following struct:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TextView&lt;/span&gt;: UIViewRepresentable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The text view must conform to the &lt;code&gt;UIViewRepresentable&lt;/code&gt; protocol, which is the protocol that allows the use of UIKit views in SwiftUI apps. To conform to the protocol, you must write the following functions:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;makeUIView&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;updateUIView&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;makeCoordinator&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The &lt;code&gt;makeUIView&lt;/code&gt; function creates and configures the view. The function takes an argument of type &lt;code&gt;Context&lt;/code&gt; and returns the type of view you want to make, which is &lt;code&gt;UITextView&lt;/code&gt; for a text view. The &lt;code&gt;Context&lt;/code&gt; type is a type alias for the context where updates to the UIKit view take place.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeUIView&lt;/span&gt;(context: Context) -&amp;gt; UITextView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; view = UITextView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.isScrollEnabled = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.isEditable = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.isUserInteractionEnabled = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.contentInset = UIEdgeInsets(top: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;left&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, bottom: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;right&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.delegate = context.coordinator&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; view&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code listing creates a text view, configures the view so people can edit large amounts of text, and adds some padding so the text isn’t on the left edge of the screen. The code also sets the view’s delegate to the context’s coordinator, which you will create shortly.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;updateUIView&lt;/code&gt; function handles updates to the view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateUIView&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; uiView: UITextView, context: Context) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I will fill in this function later.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;makeCoordinator&lt;/code&gt; function creates a coordinator so the UIKit view can communicate with data in SwiftUI.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeCoordinator&lt;/span&gt;() -&amp;gt; TextView.Coordinator {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Coordinator(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;createthecoordinator&#34;&gt;Create the Coordinator&lt;/h4&gt;&#xA;&lt;p&gt;Add a &lt;code&gt;Coordinator&lt;/code&gt; class inside the struct for the text view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Coordinator&lt;/span&gt;: NSObject, UITextViewDelegate {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; control: TextView&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; control: TextView) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.control = control&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The class inherits from &lt;code&gt;NSObject&lt;/code&gt;, which is the base class for all UIKit classes. A text view’s coordinator should conform to the &lt;code&gt;UITextViewDelegate&lt;/code&gt; protocol so it can respond to text view notifications, such as the text changing.&lt;/p&gt;&#xA;&lt;p&gt;The coordinator needs a property to hold the UIKit view and an initializer. I will be adding more to the coordinator later in the article.&lt;/p&gt;&#xA;&lt;h4 id=&#34;addthetextviewtothedocumentview&#34;&gt;Add the Text View to the Document View&lt;/h4&gt;&#xA;&lt;p&gt;The last step to adding the text view is to have the document view display it. Open the &lt;code&gt;DocumentView.Swift&lt;/code&gt; file. Inside the &lt;code&gt;body&lt;/code&gt; property you should see a VStack that contains a HStack and a button. The HStack shows the name of the file. The button lets you go back to the browser when you’re done writing.&lt;/p&gt;&#xA;&lt;p&gt;The text view should appear between the HStack and button. Add the following line of code between the HStack and button:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TextView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you build and run the project, you should be able to create a new document and type in it.&lt;/p&gt;&#xA;&lt;h3 id=&#34;connectthetextviewtothedocument&#34;&gt;Connect the Text View to the Document&lt;/h3&gt;&#xA;&lt;p&gt;For the app to do more than let people type text in a text view, you must connect the text view to the document so the text you type updates the document as well. In the document view, you should see the following variable:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: UIDocument&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This variable contains a reference to the document. Make the following changes to the variable:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: Document&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;@State&lt;/code&gt; property wrapper will allow the text view to bind to the document in order to display the document’s text. Changing the type of the variable to &lt;code&gt;Document&lt;/code&gt; is also necessary for the text view to work with the document properly.&lt;/p&gt;&#xA;&lt;p&gt;Now add the following property to the text view:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; document: Document&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;@Binding&lt;/code&gt; property wrapper binds the &lt;code&gt;document&lt;/code&gt; property in the text view to the &lt;code&gt;document&lt;/code&gt; property in the document view. The text view and document view are both pointing to the same document. The text view now has access to the document.&lt;/p&gt;&#xA;&lt;p&gt;Now that you created the binding you must go back to the document view and change the call to create the text view by supplying the document as an argument.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TextView(document: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;document)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;$&lt;/code&gt; at the start of &lt;code&gt;$document&lt;/code&gt; indicates that you are passing a binding to the text view. You must pass a binding so the document view and text view both point to the same document.&lt;/p&gt;&#xA;&lt;h4 id=&#34;filltheupdateuiviewfunction&#34;&gt;Fill the updateUIView Function&lt;/h4&gt;&#xA;&lt;p&gt;Now that the text view has access to the document, you can write the text view’s &lt;code&gt;updateUIView&lt;/code&gt; function. Set the text view’s contents to the document’s contents.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateUIView&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; uiView: UITextView, context: Context) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uiView.text = document.text&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;handlingtextchanges&#34;&gt;Handling Text Changes&lt;/h4&gt;&#xA;&lt;p&gt;One last thing to do is to update the document when the text view contents change. Add the following function to the &lt;code&gt;Coordinator&lt;/code&gt; class:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;textViewDidChange&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; textView: UITextView) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  control.document.text = textView.text&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  control.document.updateChangeCount(.done)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first line of code sets the document’s contents to the text view’s contents. The second line marks the document as changed so it will be saved.&lt;/p&gt;&#xA;&lt;h3 id=&#34;savethedocument&#34;&gt;Save the Document&lt;/h3&gt;&#xA;&lt;p&gt;At this point you’re finished with the SwiftUI material, but there’s still some work to do to finish the app. The text editor is missing one really big feature: saving text. Open the &lt;code&gt;Document.Swift&lt;/code&gt; file. Xcode created a blank &lt;code&gt;contents&lt;/code&gt; function for saving the document.&lt;/p&gt;&#xA;&lt;p&gt;What you have to do is convert the text in the document to a &lt;code&gt;Data&lt;/code&gt; object and archive that object. Apple provides the &lt;code&gt;NSKeyedArchiver&lt;/code&gt; class and an &lt;code&gt;archivedData&lt;/code&gt; function so you can do both steps in one line of code.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;contents&lt;/span&gt;(forType typeName: String) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; Any {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; NSKeyedArchiver.archivedData(withRootObject: text,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    requiringSecureCoding: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The root object is the document’s text. Requiring secure coding ensures your app will be able to unarchive the data when loading the document.&lt;/p&gt;&#xA;&lt;h3 id=&#34;loadthedocument&#34;&gt;Load the Document&lt;/h3&gt;&#xA;&lt;p&gt;After saving the document, the next task is to load the document when someone chooses a document from the browser. Xcode supplies a blank &lt;code&gt;load&lt;/code&gt; function, where you write the code to load the document from disk.&lt;/p&gt;&#xA;&lt;p&gt;The first argument to the &lt;code&gt;load&lt;/code&gt; function is the contents of the file. You must first cast the contents to the &lt;code&gt;Data&lt;/code&gt; type. Call the &lt;code&gt;NSKeyedUnarchiver&lt;/code&gt; class’s &lt;code&gt;unarchiveTopLevelObjectWithData&lt;/code&gt; function to unarchive the text from the file. The last step is to set the document’s text to the contents of the file.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt;(fromContents contents: Any, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ofType typeName: String?) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; data = contents &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? Data &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fileContents = &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? String &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  text = fileContents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;&#xA;&lt;p&gt;Now you have a simple, working text editor. You can create documents, edit text, save documents, and open them. You can use this project as a foundation for building your own text editing app, such as a Markdown editor. I have &lt;a href=&#34;https://github.com/SwiftDevJournal/SwiftUITextEditor&#34;&gt;the project on GitHub&lt;/a&gt; for you to download if you run into issues.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Using Text Views in a SwiftUI App</title>
      <link>https://swiftdevjournal.com/using-text-views-in-a-swiftui-app/</link>
      <pubDate>Fri, 20 Dec 2019 18:43:47 +0000</pubDate>
      <guid>https://swiftdevjournal.com/using-text-views-in-a-swiftui-app/</guid>
      <description>&lt;p&gt;SwiftUI currently lacks native support for text views. (Note: Xcode 12 adds text view support to SwiftUI). If you want people to enter large amounts of text in a SwiftUI app, you have to wrap a UIKit or AppKit text view. This article shows you how to use a text view in an iOS app that uses SwiftUI. Most of this material should also apply to Mac apps. Replace anything that has a &lt;code&gt;UI&lt;/code&gt; prefix with &lt;code&gt;NS&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;uiviewrepresentable&#34;&gt;UIViewRepresentable&lt;/h3&gt;&#xA;&lt;p&gt;To use &lt;code&gt;UITextView&lt;/code&gt; in a SwiftUI app, you must create a struct for the text view and have it conform to the &lt;code&gt;UIViewRepresentable&lt;/code&gt; protocol. The &lt;code&gt;UIViewRepresentable&lt;/code&gt; protocol is how you wrap UIKit views in SwiftUI apps.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TextView&lt;/span&gt;: UIViewRepresentable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Don’t forget to import the UIKit framework.&lt;/p&gt;&#xA;&lt;h4 id=&#34;createtheview&#34;&gt;Create the View&lt;/h4&gt;&#xA;&lt;p&gt;To conform to the &lt;code&gt;UIViewRepresentable&lt;/code&gt; protocol, you must add two functions to the struct you created. The first function is &lt;code&gt;makeUIView&lt;/code&gt;, which creates and configures the view. It takes an argument of type &lt;code&gt;Context&lt;/code&gt; and returns the type of view you want to create, which is &lt;code&gt;UITextView&lt;/code&gt; for a text view. The &lt;code&gt;Context&lt;/code&gt; type is a type alias for the context where updates to the UIKit view take place. The following code shows an example of creating and configuring a text view:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeUIView&lt;/span&gt;(context: Context) -&amp;gt; UITextView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; view = UITextView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.isScrollEnabled = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.isEditable = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.isUserInteractionEnabled = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  view.contentInset = UIEdgeInsets(top: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;left&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, bottom: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;right&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; view&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At a minimum you must create the view and return it. In the code sample I decided to make the text view scrollable and editable. I also added some padding so the text isn’t on the left edge of the screen.&lt;/p&gt;&#xA;&lt;h4 id=&#34;updatetheview&#34;&gt;Update the View&lt;/h4&gt;&#xA;&lt;p&gt;The second function you must write is &lt;code&gt;updateUIView&lt;/code&gt;, which handles updates to the view. The &lt;code&gt;updateUIView&lt;/code&gt; function takes two arguments: a view and a context.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateUIView&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; uiView: UITextView, context: Context) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I will be filling the function later in the article.&lt;/p&gt;&#xA;&lt;h3 id=&#34;trycreatingyourowntextview&#34;&gt;Try Creating Your Own Text View&lt;/h3&gt;&#xA;&lt;p&gt;At this point you have enough to add a text view to a SwiftUI app. Create an iOS app project in Xcode. Add a file for the &lt;code&gt;TextView&lt;/code&gt; struct. Fill the struct with the code I’ve shown so far in the article. Open the &lt;code&gt;ContentView.swift&lt;/code&gt; file and replace the text label in the &lt;code&gt;body&lt;/code&gt; property with a text view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  TextView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Build and run the app. You should be able to type in the text view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;connectingtoyourdatamodel&#34;&gt;Connecting to Your Data Model&lt;/h3&gt;&#xA;&lt;p&gt;At this point you can type in the text view, but you’ll lose what you type when you quit the app. For a text view to be useful, it needs a connection to your app’s data model.&lt;/p&gt;&#xA;&lt;p&gt;In the struct for the text view, add a property for the data model. For a simple app, you can create a &lt;code&gt;@State&lt;/code&gt; property wrapper that holds the text.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; text: String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In a real app you’re more likely to have a reference to the data model in another SwiftUI view. Use the &lt;code&gt;@Binding&lt;/code&gt; property wrapper to access data from another SwiftUI view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Binding &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; model: MyModel&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace &lt;code&gt;MyModel&lt;/code&gt; with whatever the name of your data model is.&lt;/p&gt;&#xA;&lt;p&gt;Now that you have a connection to your data model, you can fill in the &lt;code&gt;updateUIView&lt;/code&gt; function. Make the text view show the text from the data model.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateUIView&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; uiView: UITextView, context: Context) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uiView.text = model.text&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;coordinators&#34;&gt;Coordinators&lt;/h3&gt;&#xA;&lt;p&gt;In order for a UIKit view to communicate with data in SwiftUI, the view needs a coordinator. To conform to the &lt;code&gt;UIViewRepresentable&lt;/code&gt; protocol, you must add a new function to the &lt;code&gt;TextView&lt;/code&gt; struct, &lt;code&gt;makeCoordinator&lt;/code&gt;. The &lt;code&gt;makeCoordinator&lt;/code&gt; function creates the coordinator. The return type takes the form &lt;code&gt;StructName.Coordinator&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeCoordinator&lt;/span&gt;() -&amp;gt; TextView.Coordinator {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Coordinator(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next step is to set the text view’s delegate to the context’s coordinator. Add the following line of code to &lt;code&gt;makeUIView&lt;/code&gt; before the &lt;code&gt;return&lt;/code&gt; statement:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;view.delegate = context.coordinator&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The last step is to add a class for the coordinator. Create a class for the coordinator inside the struct for the text view. Make sure the name of the class matches the name you supply to the &lt;code&gt;makeCoordinator&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Coordinator&lt;/span&gt;: NSObject, UITextViewDelegate {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; control: TextView&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;init&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; control: TextView) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.control = control&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;textViewDidChange&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; textView: UITextView) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    control.model.text = textView.text&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;Coordinator&lt;/code&gt; class inherits from &lt;code&gt;NSObject&lt;/code&gt;, which is the base class for all UIKit and AppKit classes. A coordinator for a text view should conform to &lt;code&gt;UITextViewDelegate&lt;/code&gt; so it can respond to text view notifications, such as the contents of the text view changing.&lt;/p&gt;&#xA;&lt;p&gt;The coordinator needs a property for the control it’s going to coordinate. The &lt;code&gt;control&lt;/code&gt; property contains a reference to the text view.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;Coordinator&lt;/code&gt; class needs an initializer to set its view, which is the &lt;code&gt;control&lt;/code&gt; property in the code sample.&lt;/p&gt;&#xA;&lt;p&gt;The last block of code tells the coordinator to respond when the contents of the text view change. The function sets the model’s contents to the text view’s contents. If you want the text view to handle other notifications, add the functions to the coordinator.&lt;/p&gt;&#xA;&lt;h4 id=&#34;respondingtotextchangesinmacapps&#34;&gt;Responding to Text Changes in Mac Apps&lt;/h4&gt;&#xA;&lt;p&gt;Responding to text changes has more differences in Mac apps. Let’s look at the code to respond to text changes on Mac.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;textDidChange&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; notification: Notification) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; textView = notification.object &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? NSTextView &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  control.model.text = textView.string&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The name of the function is &lt;code&gt;textDidChange&lt;/code&gt;. Instead of taking the text view as an argument, it takes a notification. The &lt;code&gt;object&lt;/code&gt; property of the notification is the object that sent the notification. When entering text, the text view is the object that sends the notification that the text changed. The &lt;code&gt;guard&lt;/code&gt; statement ensures the object that sent the notification is a text view. The property to get the text in &lt;code&gt;NSTextView&lt;/code&gt; is &lt;code&gt;string&lt;/code&gt;, not &lt;code&gt;text&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;&#xA;&lt;p&gt;To use UIKit views in a SwiftUI, you must perform the following tasks:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a struct for the view that conforms to the &lt;code&gt;UIViewRepresentable&lt;/code&gt; protocol.&lt;/li&gt;&#xA;&lt;li&gt;Write the &lt;code&gt;makeUIView&lt;/code&gt; function to create and configure the view.&lt;/li&gt;&#xA;&lt;li&gt;Write the &lt;code&gt;updateUIView&lt;/code&gt; function so SwiftUI can update the view.&lt;/li&gt;&#xA;&lt;li&gt;Write the &lt;code&gt;makeCoordinator&lt;/code&gt; function to create a coordinator for your view to communicate with SwiftUI data.&lt;/li&gt;&#xA;&lt;li&gt;Create a class for the coordinator.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I have a &lt;a href=&#34;https://github.com/SwiftDevJournal/SwiftUITextEditor&#34;&gt;simple plain text editor project on GitHub&lt;/a&gt; if you want to see an example of a SwiftUI project that uses a text view.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Learn SwiftUI or UIKit?</title>
      <link>https://swiftdevjournal.com/learn-swiftui-or-uikit/</link>
      <pubDate>Tue, 03 Dec 2019 19:12:52 +0000</pubDate>
      <guid>https://swiftdevjournal.com/learn-swiftui-or-uikit/</guid>
      <description>&lt;p&gt;With the release of SwiftUI in iOS 13, a common question from people new to iOS development is whether they should learn SwiftUI or UIKit.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whylearnswiftui&#34;&gt;Why Learn SwiftUI&lt;/h3&gt;&#xA;&lt;p&gt;The most compelling reason to learn SwiftUI is it’s the future. 2–3 years from now, most iOS developers will use SwiftUI to build their user interfaces. You’re eventually going to need to learn SwiftUI so you might as well learn it now. It makes sense to learn SwiftUI instead of learning UIKit and learning SwiftUI a year or two later.&lt;/p&gt;&#xA;&lt;h3 id=&#34;swiftuilimitations&#34;&gt;SwiftUI Limitations&lt;/h3&gt;&#xA;&lt;p&gt;SwiftUI is new technology. At the time I’m writing this, SwiftUI has been out for six months, and three of those months it was in beta. Because SwiftUI is new technology, it has bugs and missing features. Apple is going to be making changes to SwiftUI over the next few years so there’s going to be a lot of work keeping up with the changes. Should you decide to learn SwiftUI instead of UIKit, prepare for a lot of frustration.&lt;/p&gt;&#xA;&lt;p&gt;Apple’s SwiftUI documentation is limited at best. Many outsiders have been &lt;a href=&#34;https://iosdevweekly.com/issues/428#comment&#34;&gt;writing books&lt;/a&gt;, articles, and tutorials on Swift UI. But at this time, everyone is a beginner at SwiftUI development. There’s much less SwiftUI learning material than UIKit.&lt;/p&gt;&#xA;&lt;p&gt;SwiftUI has a limited set of user interface elements. For example SwiftUI currently lacks text views and collection views.&lt;/p&gt;&#xA;&lt;p&gt;SwiftUI apps don’t run on iOS 12 and earlier iOS versions. For people new to iOS development, this isn’t a big limitation, but it is a limitation.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whylearnuikit&#34;&gt;Why Learn UIKit&lt;/h3&gt;&#xA;&lt;p&gt;UIKit is mature and stable. It has all the available iOS user interface elements. There is a lot more UIKit learning material available than SwiftUI.&lt;/p&gt;&#xA;&lt;p&gt;If you want to use a text view, collection view, or another view that SwiftUI doesn’t have, you need to know some UIKit.&lt;/p&gt;&#xA;&lt;h3 id=&#34;shouldyoulearnswiftuioruikit&#34;&gt;Should You Learn SwiftUI or UIKit?&lt;/h3&gt;&#xA;&lt;p&gt;If you can put up with the SwiftUI limitations I mentioned earlier and deal with limited documentation, learn SwiftUI. Otherwise learn UIKit.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Creating a Simple SwiftUI App</title>
      <link>https://swiftdevjournal.com/creating-a-simple-swiftui-app/</link>
      <pubDate>Thu, 21 Nov 2019 18:48:00 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-a-simple-swiftui-app/</guid>
      <description>&lt;p&gt;SwiftUI is Apple’s new framework for building user interfaces in Swift. Let’s introduce SwiftUI by creating a simple app. The app displays the number of times you tap a button. I couldn’t think of a simper app idea.&lt;/p&gt;&#xA;&lt;p&gt;I’m going to focus on making an iOS app in the article, but you can also make a Mac version of this app. Create a macOS App project instead of an iOS project.&lt;/p&gt;&#xA;&lt;p&gt;Apple added SwiftUI support in Xcode 11 so you must be running Xcode 11 or higher to use SwiftUI.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createtheproject&#34;&gt;Create the Project&lt;/h3&gt;&#xA;&lt;p&gt;Create a single-view iOS app (App on Xcode 12) project. Choose SwiftUI from the User Interface menu. Deselect all the checkboxes.&lt;/p&gt;&#xA;&lt;p&gt;When you create the project, the project navigator should look similar to the following screenshot:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ProjectNavigatorSwiftUIProjectStart.png&#34; alt=&#34;SwiftUI project navigator&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The file you’re going to edit in this article is &lt;code&gt;ContentView.swift&lt;/code&gt;. This file contains the main view for the app’s user interface. You will be adding controls to the content view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thecontentview&#34;&gt;The Content View&lt;/h3&gt;&#xA;&lt;p&gt;Open the &lt;code&gt;ContentView.swift&lt;/code&gt; file. You’ll see the following struct for the content view:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContentView&lt;/span&gt;: View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;body&lt;/code&gt; property contains the main view. In the code Apple supplies, the view consists of a label (the &lt;code&gt;Text&lt;/code&gt; struct is a label) with the text &lt;code&gt;Hello, World!&lt;/code&gt;. If you build and run the project, you will see the label.&lt;/p&gt;&#xA;&lt;h3 id=&#34;previewsandthecanvas&#34;&gt;Previews and the Canvas&lt;/h3&gt;&#xA;&lt;p&gt;If you look at the end of the &lt;code&gt;ContentView.swift&lt;/code&gt; file, you’ll see the following struct:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContentView_Previews&lt;/span&gt;: PreviewProvider {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; previews: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ContentView()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That struct is for displaying a preview of the view in Xcode’s canvas. The canvas is next to the Swift file in Xcode so you can view your source code and the canvas side by side..&lt;/p&gt;&#xA;&lt;p&gt;I’m not going to use previews and the canvas in this article. I find the canvas gets in the way, is flaky, and doesn’t help much. But the canvas is there for you if you want it. You can toggle the canvas on and off using a button on the right side of the jump bar.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ToggleCanvas.png&#34; alt=&#34;toggle canvas&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The button is at the top left in the screenshot.&lt;/p&gt;&#xA;&lt;h3 id=&#34;changethelabel&#34;&gt;Change the Label&lt;/h3&gt;&#xA;&lt;p&gt;Let’s start by changing the label’s text to &lt;code&gt;Taps:&lt;/code&gt;. Change the code for &lt;code&gt;body&lt;/code&gt; to the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Taps: &amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Build and run the project, and you should see the label’s text is &lt;code&gt;Taps:&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;You can modify how the text in the label looks using functions and properties of the &lt;code&gt;Text&lt;/code&gt; struct. Start with a period. The following code displays the label in bold text:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Taps: &amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .bold()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following code changes the font to the system title font:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Taps: &amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#x9;.font(.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;addavariabletostorethetapcount&#34;&gt;Add a Variable to Store the Tap Count&lt;/h3&gt;&#xA;&lt;p&gt;To display the number of times someone taps the button, you need a variable to store the number of taps. Add the following code before the &lt;code&gt;body&lt;/code&gt; variable:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@State &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; taps = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You must use the &lt;code&gt;@State&lt;/code&gt; property wrapper so you can change the value of &lt;code&gt;taps&lt;/code&gt; when someone taps the button. If you omit the &lt;code&gt;@State&lt;/code&gt; part, you will get a compiler error saying that you’re trying to change an immutable value.&lt;/p&gt;&#xA;&lt;p&gt;Now modify the label so it also shows the number of taps.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Taps: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;taps&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Build and run the project. The label will show zero taps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;placethelabelinastack&#34;&gt;Place the Label in a Stack&lt;/h3&gt;&#xA;&lt;p&gt;The next logical step is to add a button. But you can’t just add the button after the label.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; body: some View {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Taps: &amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .font(.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// This won&amp;#39;t compile.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Button(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Tap Me&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The compiler will complain about that code. You have to place the label and button inside a stack. Start by placing the label inside a stack.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VStack {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Taps: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;taps&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .font(.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I placed the label in a vertical stack. When you add the button, it will appear below the label. Build and run the project. There aren’t any visible changes, but you’re ready to add the button now.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addthebutton&#34;&gt;Add the Button&lt;/h3&gt;&#xA;&lt;p&gt;Let’s add the button to the stack in the content view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VStack {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Taps: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;taps&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .font(.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Button(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Tap Me&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.taps &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The button’s title, &lt;code&gt;Tap Me&lt;/code&gt;, is in parentheses. A closure for the button’s action (what happens when someone taps the button) follows. For this app you increment the &lt;code&gt;taps&lt;/code&gt; variable. If you have more complicated behavior, write a function and call that function from the closure.&lt;/p&gt;&#xA;&lt;p&gt;Build and run the project. The number of taps increases each time you tap the button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addspacebetweenthelabelandbutton&#34;&gt;Add Space Between the Label and Button&lt;/h3&gt;&#xA;&lt;p&gt;The app works, but there’s not much space between the label and button. Use the &lt;code&gt;padding&lt;/code&gt; function to add some padding between the label and button.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VStack {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Text(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Taps: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;\(&lt;/span&gt;taps&lt;span style=&#34;color:#e6db74&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .font(.title)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .padding()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Button(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Tap Me&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.taps &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you supply no arguments, the &lt;code&gt;padding&lt;/code&gt; function adds a small amount of space. To add more space, you can supply the edge to apply the padding and the amount. The following line of code provides 100 points of padding at the bottom:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.padding(.bottom, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you build and run the project, you should see better spacing between the label and button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;challenge&#34;&gt;Challenge&lt;/h3&gt;&#xA;&lt;p&gt;Add a Reset button that sets the &lt;code&gt;taps&lt;/code&gt; variable back to zero. Don’t forget to add padding between the two buttons. I have the &lt;a href=&#34;https://github.com/SwiftDevJournal/ButtonTapCounter&#34;&gt;project on GitHub&lt;/a&gt; if you get stuck.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Going from Tutorials to Your First Real Swift App: First Steps</title>
      <link>https://swiftdevjournal.com/going-from-tutorials-to-your-first-real-app-first-steps/</link>
      <pubDate>Wed, 13 Nov 2019 19:45:55 +0000</pubDate>
      <guid>https://swiftdevjournal.com/going-from-tutorials-to-your-first-real-app-first-steps/</guid>
      <description>&lt;p&gt;If you want to learn iOS development, &lt;a href=&#34;https://www.swiftdevjournal.com/learning-ios-development/&#34;&gt;there are many places&lt;/a&gt; for you to learn. &lt;a href=&#34;https://www.hackingwithswift.com/&#34;&gt;Hacking with Swift&lt;/a&gt; has two free 100 day courses for learning iOS development, one with UIKit and one with SwiftUI.&lt;/p&gt;&#xA;&lt;p&gt;Getting started with iOS development normally isn’t the big issue. Go through a book or course, and you’ll learn the basics of iOS programming. The trouble starts when you finish a book or course and start to make your first app on your own. You feel stuck and don’t know where to start. You share some of the following feelings:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;“I’m a little lost as to where to go next. I’ve completed Swift for Beginners courses on at least four different sites, and if I build one more My First App I may cry.”&lt;/li&gt;&#xA;&lt;li&gt;“I just am having a hard time finding the tutorials/courses I specifically need to acquire the skills I need for MY project. I’m frankly not even sure I know what skills I actually need because so much of the information I’m seeing is so outdated that I’m not sure it’s relevant to me or if I’ll begin working on it only to find it’s no longer the way things are done or that there’s a better way after I’ve put in a lot of effort.”&lt;/li&gt;&#xA;&lt;li&gt;“Making the jump from basic concepts to actual coding is hard.”&lt;/li&gt;&#xA;&lt;li&gt;“Basic lessons have very basic concepts but when I look at the code being used in other projects, they use methods and syntax I’ve never seen.”&lt;/li&gt;&#xA;&lt;li&gt;“I watched almost every video (Stanford course) and I did everything that professor do. I built them all. But when I’m trying to build apps alone, even the things I built earlier I can’t do anything. I know Swift syntax and other stuff but I just can’t program.”&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;whydoyoufeelstuck&#34;&gt;Why Do You Feel Stuck?&lt;/h3&gt;&#xA;&lt;p&gt;When you were following the book, course, or tutorial, you were doing the equivalent of watching someone make an app. You weren’t making the app. When you try to make your own app, you get stuck because you don’t have the book, course, or tutorial telling you what to do.&lt;/p&gt;&#xA;&lt;p&gt;To apply to what you learned, you have to make an app on your own. And there’s a lot less material on going from beginner to making your first real app than there is on getting started.&lt;/p&gt;&#xA;&lt;h3 id=&#34;step1:chooseasuitableproject&#34;&gt;Step 1: Choose a Suitable Project&lt;/h3&gt;&#xA;&lt;p&gt;The first step you have to take when creating an app is choosing the app to make. When choosing an app to make, you must balance the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Making something small enough that you can finish.&lt;/li&gt;&#xA;&lt;li&gt;Making something that interests you.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A big mistake many new iOS developers make is starting with a huge app. They want to make something like Uber or a social media app with realtime chat, something that requires people to sign up for an account to use the app. Making a social media app requires you to have a backend server with a database to store all the data. No iOS development tutorial or book is going to teach you things like that. No wonder people feel stuck.&lt;/p&gt;&#xA;&lt;p&gt;For your first app make something small and relatively simple. Make an app that uses only Apple technologies. Make something that you have a chance to finish. Once you finish your first app, choose something more ambitious as your next project.&lt;/p&gt;&#xA;&lt;p&gt;But you also have to make an app that interests you. If you choose an app that bores you, you’ll stop making it.&lt;/p&gt;&#xA;&lt;h3 id=&#34;step2:learnthenecessaryframeworkstomakeyourapp&#34;&gt;Step 2: Learn the Necessary Frameworks to Make Your App&lt;/h3&gt;&#xA;&lt;p&gt;You may be able to skip this step if you pick a simple enough app to make. But most projects force you to learn some additional frameworks to make the app.&lt;/p&gt;&#xA;&lt;p&gt;If you open Xcode’s documentation window (choose Help &amp;gt; Developer Documentation in Xcode), you’ll see that Apple has dozens of frameworks for iOS developers. There’s no way for you to learn them all. Use your choice of project to determine the frameworks you need to learn.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A fitness app may use HealthKit.&lt;/li&gt;&#xA;&lt;li&gt;An app that uses locations may use MapKit.&lt;/li&gt;&#xA;&lt;li&gt;A text editing app uses TextKit. You may even need to learn about &lt;code&gt;UIDocument&lt;/code&gt; and making document-based apps.&lt;/li&gt;&#xA;&lt;li&gt;A drawing app may use PencilKit and Quartz2D.&lt;/li&gt;&#xA;&lt;li&gt;An app that generates PDF files uses PDFKit and possibly Quartz2D.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;step3:doalittleplanning&#34;&gt;Step 3: Do a Little Planning&lt;/h3&gt;&#xA;&lt;p&gt;You may be tempted to create a new project in Xcode and start writing code. But development will go more smoothly if you do some planning before you start writing code. You don’t have to plan everything upfront, but doing the following will help you:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Draw the screens for the app on paper&lt;/li&gt;&#xA;&lt;li&gt;Make a list of the app’s must-have features&lt;/li&gt;&#xA;&lt;li&gt;Make a list of the types of data your app uses&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Once you do some planning, pick the simplest feature you can implement and work on that. When you get a small part working, you’ll feel good and use that energy to move on to the next part of the app. Build the app piece by piece, and you’ll eventually finish your first app.&lt;/p&gt;&#xA;&lt;h3 id=&#34;areyoudoingitright&#34;&gt;Are You Doing It Right?&lt;/h3&gt;&#xA;&lt;p&gt;You may be wondering as you develop your app if you’re doing things the right way. I can’t tell you if you are, but it’s software, not something physical. Code can be changed and improved. If you find out you’re doing things wrong, you can change the code so you’re doing thing the right way.&lt;/p&gt;&#xA;&lt;p&gt;I recommend placing your project under version control. Using version control makes your code easier to change. If you make a bunch of mistakes, you can go back to a working version of your code. When you create a project in Xcode, there’s a checkbox to place your project under version control. You can place an existing Xcode project under version control by choosing Source Control &amp;gt; Create Git Repositories.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Accessing the SwiftUI Views Library in Xcode</title>
      <link>https://swiftdevjournal.com/accessing-the-swiftui-views-library-in-xcode/</link>
      <pubDate>Mon, 11 Nov 2019 05:04:37 +0000</pubDate>
      <guid>https://swiftdevjournal.com/accessing-the-swiftui-views-library-in-xcode/</guid>
      <description>&lt;p&gt;Are you running macOS 10.15 and trying to build a SwiftUI user interface visually? Are you having trouble finding the SwiftUI user interface elements, the SwiftUI equivalent of Xcode’s object library for storyboards?&lt;/p&gt;&#xA;&lt;p&gt;When you click the Add button in the toolbar, Xcode shows the code snippets library instead of the view library. You must click the View Library button in the library window to access the SwiftUI views.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SwiftUIViewsLibrary.png&#34; alt=&#34;SwiftUI views library&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The View Library button is the left button in the group of five buttons in the screenshot. The canvas must be open for the View Library button to appear in the library window. Once you have access to the view library, you can drag views to the canvas and build your interface visually.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Timers in Swift</title>
      <link>https://swiftdevjournal.com/timers/</link>
      <pubDate>Tue, 05 Nov 2019 18:20:16 +0000</pubDate>
      <guid>https://swiftdevjournal.com/timers/</guid>
      <description>&lt;p&gt;A timer sends a message to an object after a certain amount of time passes. Start by declaring a variable for the timer.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; saveTimer = Timer()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;startingatimer&#34;&gt;Starting a Timer&lt;/h3&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;scheduledTimer&lt;/code&gt; method to start a timer. The &lt;code&gt;scheduledTimer&lt;/code&gt; method takes the following arguments:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A time interval for how often the timer fires, specified in seconds.&lt;/li&gt;&#xA;&lt;li&gt;Target, which is the object that receives the message from the timer.&lt;/li&gt;&#xA;&lt;li&gt;Selector, which is the function the target should run after receiving the message.&lt;/li&gt;&#xA;&lt;li&gt;UserInfo, which is optional additional information you can send.&lt;/li&gt;&#xA;&lt;li&gt;Repeats, which indicates whether the timer runs once or repeats.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The following code starts a timer to autosave data every 30 seconds:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;startTimer&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  saveTimer = Timer.scheduledTimer(timeInterval: &lt;span style=&#34;color:#ae81ff&#34;&gt;30.0&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    target: &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;, selector: &lt;span style=&#34;color:#66d9ef&#34;&gt;#selector&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.autosave),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    userInfo: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, repeats: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function for the selector needs &lt;code&gt;@objc&lt;/code&gt; at the start of the declaration.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@objc&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;autosave&lt;/span&gt;(timer: Timer) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;stoppingatimer&#34;&gt;Stopping a Timer&lt;/h3&gt;&#xA;&lt;p&gt;Call the &lt;code&gt;invalidate&lt;/code&gt; method to stop a timer. The following code stops a timer:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stopTimer&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  saveTimer.invalidate()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Xcode Missing View Controllers</title>
      <link>https://swiftdevjournal.com/xcode-11-missing-view-controllers/</link>
      <pubDate>Sun, 13 Oct 2019 20:24:35 +0000</pubDate>
      <guid>https://swiftdevjournal.com/xcode-11-missing-view-controllers/</guid>
      <description>&lt;p&gt;I have seen a lot of questions recently from people who are creating iOS projects in Xcode and not being able to find the &lt;code&gt;ViewController.swift&lt;/code&gt; file and not being able to find view controllers. Usually these questions come from people who are following a tutorial written with an earlier version of Xcode.&lt;/p&gt;&#xA;&lt;p&gt;The cause of the issue is that Xcode defaults to using SwiftUI for new iOS and Mac projects.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode11UserInterfaceMenu.png&#34; alt=&#34;user interface menu&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;SwiftUI is a new framework from Apple for making user interfaces for Apple devices. SwiftUI does not use view controllers so when you create a SwiftUI project, there aren’t going to be any view controllers in the project.&lt;/p&gt;&#xA;&lt;p&gt;The solution to the issue is to choose Storyboard from the User Interface menu when you create the project. When you tell Xcode to use storyboards for the user interface, your project will include a view controller and a &lt;code&gt;ViewController.swift&lt;/code&gt; file.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Limiting an iOS App to Friends and Family</title>
      <link>https://swiftdevjournal.com/limiting-an-ios-app-to-friends-and-family/</link>
      <pubDate>Thu, 10 Oct 2019 17:46:47 +0000</pubDate>
      <guid>https://swiftdevjournal.com/limiting-an-ios-app-to-friends-and-family/</guid>
      <description>&lt;p&gt;I sometimes see questions on forums from people who have developed an iOS app and want only friends and family to be able to install the app. Apple does not currently allow you to restrict an app to friends and family, but there are two alternatives that will allow you to effectively reach that goal.&lt;/p&gt;&#xA;&lt;h3 id=&#34;update&#34;&gt;Update&lt;/h3&gt;&#xA;&lt;p&gt;Apple now has &lt;a href=&#34;https://developer.apple.com/support/unlisted-app-distribution/&#34;&gt;unlisted app distribution&lt;/a&gt; for releasing apps that won’t appear in App Store listings.&lt;/p&gt;&#xA;&lt;h3 id=&#34;puttheappontheappstore&#34;&gt;Put the App on the App Store&lt;/h3&gt;&#xA;&lt;p&gt;The simplest solution is to just put your app on the App Store. Many of you think this is a bad idea, that putting your app on the App Store will allow anyone with an iOS device to install the app.&lt;/p&gt;&#xA;&lt;p&gt;Technically you’re correct. When you put an app on the iOS App Store, anyone can install the app. But no one will know your app exists. The only people who will install your app are the people you tell about the app.&lt;/p&gt;&#xA;&lt;p&gt;In early 2017 I released a free word game for iOS and Mac, &lt;a href=&#34;https://www.checksimgames.com/letterminer/&#34;&gt;LetterMiner&lt;/a&gt;. When I released the game I got a few dozen downloads on the iOS App Store due to the game being new. But then the downloads dried up. In almost three years, I have had fewer than 100 downloads of the iOS version. And I wanted people to play the game.&lt;/p&gt;&#xA;&lt;p&gt;As long as you don’t publicize the app, your app will effectively be limited to your inner circle of friends and family. You may get a few outside downloads when you first release the app, but after that the downloads will trickle down to zero. There are so many apps on the App Store that people are not going to stumble upon your app by browsing the store.&lt;/p&gt;&#xA;&lt;h3 id=&#34;keeptheappperpetuallyinbeta&#34;&gt;Keep the App Perpetually in Beta&lt;/h3&gt;&#xA;&lt;p&gt;A more complicated solution is to keep your app perpetually in beta and add your family and friends as beta testers in &lt;a href=&#34;https://testflight.apple.com&#34;&gt;TestFlight&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The advantage of TestFlight is that no outsiders will be able to install your app. The disadvantage is that you have to submit a new beta build every 90 days. That’s why I recommend putting your app on the App Store. Release your app once and as long as you avoid publicizing the app, you will reach your goal of limiting your iOS app to friends and family.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Introducing the Swift Package Manager</title>
      <link>https://swiftdevjournal.com/introducing-the-swift-package-manager/</link>
      <pubDate>Thu, 12 Sep 2019 17:39:39 +0000</pubDate>
      <guid>https://swiftdevjournal.com/introducing-the-swift-package-manager/</guid>
      <description>&lt;p&gt;Xcode 11’s improved support for the Swift Package Manager simplifies adding and updating third party frameworks in your projects. In this article you’ll learn how to use the Swift Package Manager to add third party frameworks to your apps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;accessingtheswiftpackages&#34;&gt;Accessing the Swift Packages&lt;/h3&gt;&#xA;&lt;p&gt;You can access the Swift packages by selecting your project from the project navigator and clicking the Swift Packages button at the top of the project editor.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SwiftPackagesList.png&#34; alt=&#34;Swift packages list&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Initially the list of Swift packages is empty.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addingaswiftpackagetoyourproject&#34;&gt;Adding a Swift Package to Your Project&lt;/h3&gt;&#xA;&lt;p&gt;Click the Add button to add a package to your project. Enter the name of the package or the URL of the package repository in the search field. You’ll get more accurate results if you know the repository URL. The following screenshot shows a search for the SwiftCheck testing library:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ChoosePackageStep1.png&#34; alt=&#34;choose package&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;After choosing the package to add, click the Next button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;specifyingversionrules&#34;&gt;Specifying Version Rules&lt;/h3&gt;&#xA;&lt;p&gt;The next step is to specify the rules for what version of the package to use. You can choose a version, a branch from the git repository, or a specific git commit. Most of the time, you’ll either use a version or a branch. Using the master branch would ensure you’re using the latest stable version.&lt;/p&gt;&#xA;&lt;p&gt;Xcode provides four different version rules.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Up to next major. If the current version of the package is 1.1, it will use the latest 1.x version. It won’t use version 2 of the package.&lt;/li&gt;&#xA;&lt;li&gt;Up to next minor. If the current version of the package is 1.1, it will use the latest 1.1.x version. It won’t use version 1.2 of the package.&lt;/li&gt;&#xA;&lt;li&gt;Range, which lets you specify the version ranges of the package to use.&lt;/li&gt;&#xA;&lt;li&gt;Exact, which uses a specific version of the package.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Xcode defaults to using up to next major. Click the Next button. Xcode will generate the package for you. Click the Finish button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;viewingthedependencies&#34;&gt;Viewing the Dependencies&lt;/h3&gt;&#xA;&lt;p&gt;After adding a Swift package to your project, the project navigator will show the Swift package dependencies.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SwiftPackageDependencies.png&#34; alt=&#34;package dependencies&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Adding the SwiftCheck package dependency to the project also adds the packages SwiftCheck depends on: FileCheck, llbuild, SwiftPM, and Rainbow. Xcode added the dependencies without me having to do anything. Now I can import the SwiftCheck module into my unit testing classes and use SwiftCheck to generate test cases for me.&lt;/p&gt;&#xA;&lt;h3 id=&#34;changingarule&#34;&gt;Changing a Rule&lt;/h3&gt;&#xA;&lt;p&gt;Suppose you made a mistake specifying a version rule when you added a Swift package to your project. How do you change the rule?&lt;/p&gt;&#xA;&lt;p&gt;Access the list of Swift packages in your project from the project editor. Double-click on the package to open a sheet to change the rule.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SwiftPackageChangeRule.png&#34; alt=&#34;package change rule&#34;&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Create a Document-Based Mac App in Swift</title>
      <link>https://swiftdevjournal.com/create-a-document-based-mac-app-in-swift/</link>
      <pubDate>Thu, 15 Aug 2019 19:05:09 +0000</pubDate>
      <guid>https://swiftdevjournal.com/create-a-document-based-mac-app-in-swift/</guid>
      <description>&lt;p&gt;The Mac development series continues with an article on making document-based apps. You’re going to learn about document-based apps by making a plain text editor.&lt;/p&gt;&#xA;&lt;p&gt;If you’re new to Mac development, read the following articles before reading this one:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/introduction-to-mac-development-create-a-project/&#34;&gt;Introduction to Mac Development: Create a Project&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/introduction-to-mac-development-build-the-ui/&#34;&gt;Introduction to Mac Development: Build the UI&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/introduction-to-mac-development-connecting-ui-elements/&#34;&gt;Introduction to Mac Development: Connecting UI Elements&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.swiftdevjournal.com/make-a-simple-mac-app-in-swift/&#34;&gt;Make a Simple Mac App in Swift&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Those articles go into more detail on things that I gloss over in this article.&lt;/p&gt;&#xA;&lt;h3 id=&#34;document-basedapps&#34;&gt;Document-Based Apps&lt;/h3&gt;&#xA;&lt;p&gt;A document-based app lets people create documents, where each document is stored in its own file. On the Mac document-based apps take advantage of the File menu. The New menu item creates a new document. The Open menu item opens a document. The Save menu item saves the document. Examples of document-based apps are text editors, spreadsheets, and drawing apps.&lt;/p&gt;&#xA;&lt;p&gt;Apple provides the &lt;code&gt;NSDocument&lt;/code&gt; class for Mac apps to work with documents. When you create a document-based app project in Xcode, Xcode provide a subclass of &lt;code&gt;NSDocument&lt;/code&gt; for you to work with.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createtheproject&#34;&gt;Create the Project&lt;/h3&gt;&#xA;&lt;p&gt;Start by creating a new project in Xcode. Choose File &amp;gt; New &amp;gt; Project to open the New Project Assistant. Choose Cocoa App from the list of Mac app project templates. Click the Next button.&lt;/p&gt;&#xA;&lt;p&gt;Enter the project name in the Product Name text field. Select the Use Storyboards and Create Document-Based Application checkboxes. Deselect the Use Core Data and Use SwiftUI (Xcode 11 and later) checkboxes. Enter &lt;code&gt;txt&lt;/code&gt; in the Document Extension text field because a plain text editor saves plain text files.&lt;/p&gt;&#xA;&lt;p&gt;Click the Next button. Choose a location to save the project. Click the Create button to finish creating the project.&lt;/p&gt;&#xA;&lt;h3 id=&#34;projectfiles&#34;&gt;Project Files&lt;/h3&gt;&#xA;&lt;p&gt;There are three files you will work on in the project.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Main.storyboard&lt;/code&gt; contains the user interface.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ViewController.swift&lt;/code&gt; contains the code for the view controller.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Document.swift&lt;/code&gt; contains the code for the document. The document is a subclass of &lt;code&gt;NSDocument&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The names &lt;code&gt;ViewController&lt;/code&gt; and &lt;code&gt;Document&lt;/code&gt; are generic. I kept these names for this project because there’s only one view controller in the project and a text editor deals with documents. If you write your own document-based applications, you would benefit from renaming the classes and files &lt;code&gt;ViewController&lt;/code&gt; and &lt;code&gt;Document&lt;/code&gt; to something more descriptive.&lt;/p&gt;&#xA;&lt;h3 id=&#34;dealingwiththeappsandbox&#34;&gt;Dealing with the App Sandbox&lt;/h3&gt;&#xA;&lt;p&gt;When you create a new Cocoa project in Xcode, the App Sandbox is turned on. The initial permissions for dealing with user selected files in the sandbox is read-only. This means that you will be unable to open a Save panel to save the document.&lt;/p&gt;&#xA;&lt;p&gt;There are two ways to fix the issue. First, you can turn off the App Sandbox. Second, you can set the permission and access for user selected files to Read/Write&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AppSandboxFileAccess.png&#34; alt=&#34;app sandbox file access&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;You can access the App Sandbox settings by selecting the project from the project navigator, selecting the app target from the project editor, and clicking the Capabilities button at the top of the project editor.&lt;/p&gt;&#xA;&lt;h3 id=&#34;buildtheuserinterface&#34;&gt;Build the User Interface&lt;/h3&gt;&#xA;&lt;p&gt;The user interface for this project is simple. It consists of a text view that covers the whole window.&lt;/p&gt;&#xA;&lt;p&gt;Open the storyboard. Delete the label in the window that says &lt;code&gt;Your document contents here&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Open the Object Library and type &lt;code&gt;text view&lt;/code&gt; in the search field. Drag the Plain Document Content Text View item from the Object Library to the view controller on the storyboard canvas. If you are running an older version of Xcode that doesn’t have a plain document content text view, drag a text view to the view controller.&lt;/p&gt;&#xA;&lt;p&gt;Resize the text view so it fills the whole view. Select the text view’s enclosing scroll view and open the size inspector. Click the two arrows in the inner autoresizing square. Clicking the arrows will ensure the text view fills the whole window when the window resizes.&lt;/p&gt;&#xA;&lt;p&gt;If your version of Xcode doesn’t have a plain document content text view, select the text view and open the attributes inspector. Deselect the Allows Rich Text checkbox.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createanoutletforthetextview&#34;&gt;Create an Outlet for the Text View&lt;/h3&gt;&#xA;&lt;p&gt;The next step is to create an outlet for the text view so you can access it in your code. Open the assistant editor and make sure both the storyboard and view controller source code file are open. Select the text view in the storyboard and control-drag inside the &lt;code&gt;ViewController&lt;/code&gt; class to create an outlet for the text view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addpropertiestothedocumentclass&#34;&gt;Add Properties to the Document Class&lt;/h3&gt;&#xA;&lt;p&gt;Now it’s time to start writing some code by adding some properties to the &lt;code&gt;Document&lt;/code&gt; class. There are two properties to add. The first property stores the contents of the document. You’re going to need this property when loading the document.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; contents = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second property is a computed property to access the view controller. When saving the document, you’re going to set the &lt;code&gt;contents&lt;/code&gt; property to the text view’s contents. To access the text view, the document needs access to the view controller.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; viewController: ViewController? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; windowControllers.first?.contentViewController &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? ViewController&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code takes advantage of the fact the document has only one window controller. Access the first item in the &lt;code&gt;windowControllers&lt;/code&gt; array and get its content view controller.&lt;/p&gt;&#xA;&lt;h3 id=&#34;savingthedocument&#34;&gt;Saving the Document&lt;/h3&gt;&#xA;&lt;p&gt;The text view handles common text editing tasks without you having to write any code. For this project the only code you have to write is the code to save and load documents.&lt;/p&gt;&#xA;&lt;p&gt;To save the document you must write the &lt;code&gt;dataOfType&lt;/code&gt; function. Xcode provides a shell of the function for you to fill in, which you can find in the &lt;code&gt;Document.swift&lt;/code&gt; file.&lt;/p&gt;&#xA;&lt;p&gt;Set the document’s &lt;code&gt;contents&lt;/code&gt; property to the text view’s string. Convert the document contents to a &lt;code&gt;Data&lt;/code&gt; object by using the &lt;code&gt;String&lt;/code&gt; struct’s &lt;code&gt;data&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;(ofType typeName: String) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; Data {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Save the text view contents to disk&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; textView = viewController?.textView {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    contents = textView.string&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; contents.data(using: .utf8) ?? Data()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; NSError(domain: NSOSStatusErrorDomain, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    code: unimpErr, userInfo: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that you don’t have to write any code to open a Save panel. Cocoa’s document architecture handles opening the Save and Open panels for you.&lt;/p&gt;&#xA;&lt;h3 id=&#34;loadingthedocument&#34;&gt;Loading the Document&lt;/h3&gt;&#xA;&lt;p&gt;To load the document you must write the &lt;code&gt;readFromData&lt;/code&gt; function. Xcode provides a shell of the function for you to fill in. The shell has a &lt;code&gt;throw&lt;/code&gt; statement in the function. Remove that line of code. If you keep that line, an alert will open when you try to open a document saying that the document can’t be opened.&lt;/p&gt;&#xA;&lt;p&gt;Loading involves converting a &lt;code&gt;Data&lt;/code&gt; object to a string and setting the document’s &lt;code&gt;contents&lt;/code&gt; property to that string. The &lt;code&gt;String&lt;/code&gt; struct has an initializer that takes a &lt;code&gt;Data&lt;/code&gt; object as an argument.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(from data: Data, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ofType typeName: String) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fileContents = String(data: data, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    encoding: .utf8) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    contents = fileContents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;fillingthetextview&#34;&gt;Filling the Text View&lt;/h3&gt;&#xA;&lt;p&gt;After loading the document from disk, fill the text view with the document’s contents. Your first instinct may be to fill the text view from the &lt;code&gt;readFromData&lt;/code&gt; function. If you do that, you’ll find the view controller is nil, and you won’t be able to access the text view.&lt;/p&gt;&#xA;&lt;p&gt;What you have to do is override the function &lt;code&gt;viewDidAppear&lt;/code&gt; in the view controller. Gain access to the document through the view controller’s window controller and set the text view’s string to the document’s contents.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;viewDidAppear&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Fill the text view with the document&amp;#39;s contents.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; document = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.view.window?.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    windowController?.document &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? Document {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    textView.string = document.contents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;&#xA;&lt;p&gt;If you made it this far, congratulations. You wrote a usable text editor. Adding a text view provides most basic text editing functions so you don’t have to reinvent common behavior. Cocoa’s document architecture handles opening Save and Open panels, reducing the amount of code you have to write. There’s fewer than 20 lines of code to write in this project.&lt;/p&gt;&#xA;&lt;p&gt;The project &lt;a href=&#34;https://github.com/SwiftDevJournal/PlainTextEditor&#34;&gt;is on GitHub&lt;/a&gt; for you to download if you have trouble building or running the project.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Why Make Mac Apps?</title>
      <link>https://swiftdevjournal.com/why-make-mac-apps/</link>
      <pubDate>Wed, 07 Aug 2019 17:28:07 +0000</pubDate>
      <guid>https://swiftdevjournal.com/why-make-mac-apps/</guid>
      <description>&lt;p&gt;Why would anyone want to make Mac apps? Apple sells way more iPhones than Macs. Why not go where the people are and just develop iOS apps?&lt;/p&gt;&#xA;&lt;p&gt;But there are valid reasons, especially business reasons, to make Mac apps.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;You don’t have to pay an annual fee to Apple.&lt;/li&gt;&#xA;&lt;li&gt;You can distribute apps from your website.&lt;/li&gt;&#xA;&lt;li&gt;You can make what you want.&lt;/li&gt;&#xA;&lt;li&gt;Mac users buy apps.&lt;/li&gt;&#xA;&lt;li&gt;Less competition.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;notpayingapplesannualfee&#34;&gt;Not Paying Apple’s Annual Fee&lt;/h3&gt;&#xA;&lt;p&gt;Have you ever wanted to make an iOS app for your personal use? You have to join Apple’s paid developer program, pay Apple $99(US) each year and put the app on the App Store. The only alternatives are to jailbreak your iOS device or reinstall the app every week with a fresh provisioning profile.&lt;/p&gt;&#xA;&lt;p&gt;You can make a Mac app for your personal use without paying Apple every year. Download Xcode, create a Cocoa application project, develop the project, and run it on your Mac.&lt;/p&gt;&#xA;&lt;h3 id=&#34;distributingoutsidetheappstore&#34;&gt;Distributing Outside the App Store&lt;/h3&gt;&#xA;&lt;p&gt;Suppose you want to start a business selling software. If you want to sell iOS apps, you have to pay the annual fee, get your app approved by Apple, and have Apple take 30 percent of each sale.&lt;/p&gt;&#xA;&lt;p&gt;To distribute and sell a Mac app, all you need is a website and a payment processor, such as Paddle or FastSpring. Upload your app to your website and create an account with a payment processor. Payment processors usually take around 10 percent of each sale. With a Mac app you can keep 20 percent more of each sale.&lt;/p&gt;&#xA;&lt;h3 id=&#34;makewhatyouwant&#34;&gt;Make What You Want&lt;/h3&gt;&#xA;&lt;p&gt;You don’t need Apple’s permission to distribute Mac apps. If you want the freedom to make the apps you want, make Mac apps instead of iOS apps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;macusersbuyapps&#34;&gt;Mac Users Buy Apps&lt;/h3&gt;&#xA;&lt;p&gt;Mobile users want apps to be free or cost a few dollars at most. That’s a hard way to sustain a business.&lt;/p&gt;&#xA;&lt;p&gt;Mac users are willing to pay more for software, especially if it’s an app they use to get work done. It’s going to be easier to get a few thousand people to pay $50(US) for a Mac app than to get tens of thousands of people to buy an iOS app at any price.&lt;/p&gt;&#xA;&lt;h3 id=&#34;lesscompetition&#34;&gt;Less Competition&lt;/h3&gt;&#xA;&lt;p&gt;Apple sells way more iPhones and iPads than Macs. But there are also lots more iOS developers and iOS apps than Mac apps. Good luck getting someone to stumble upon your app by browsing the App Store.&lt;/p&gt;&#xA;&lt;p&gt;Apple sells millions of Macs each year. Presumably some of these people are also buying software for their Macs. A market with millions of potential customers and relatively few competitors is easier to reach.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wanttolearnaboutmakingmacapps&#34;&gt;Want to Learn About Making Mac Apps?&lt;/h3&gt;&#xA;&lt;p&gt;I wrote a &lt;a href=&#34;https://swiftdevjournal.com/swift-dev-journal-intro-to-cocoa&#34;&gt;book on Mac development&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Building a Product Business: the 30×500 Method</title>
      <link>https://swiftdevjournal.com/building-a-product-business-the-30x500-method/</link>
      <pubDate>Mon, 22 Jul 2019 19:27:57 +0000</pubDate>
      <guid>https://swiftdevjournal.com/building-a-product-business-the-30x500-method/</guid>
      <description>&lt;p&gt;Many Swift developers dream of building a business developing their own products. I found a realistic method of building a product business, the 30×500 method, which was developed by Alex Hillman and Amy Hoy at &lt;a href=&#34;https://stackingthebricks.com&#34;&gt;Stacking the Bricks&lt;/a&gt;. The method is geared towards people with full-time jobs who want to start a product business on the side and build a full-time business from there. This article provides an introduction to the 30×500 method.&lt;/p&gt;&#xA;&lt;h3 id=&#34;chooseanaudiencetoserve&#34;&gt;Choose an Audience to Serve&lt;/h3&gt;&#xA;&lt;p&gt;Instead of choosing a product idea and hoping that people will buy it, start with an audience to serve. Research the audience, find what they need, and come up with a product that serves one of their needs.&lt;/p&gt;&#xA;&lt;p&gt;A good audience has the following characteristics:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;They hang out online.&lt;/li&gt;&#xA;&lt;li&gt;They buy things.&lt;/li&gt;&#xA;&lt;li&gt;They share information.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you’re not sure of what audience to serve, start with an audience that you already are in. Most of the people reading this article are Swift developers making apps for Apple platforms so I will use Swift developers as the example audience for the rest of this article.&lt;/p&gt;&#xA;&lt;h3 id=&#34;findyouraudienceswateringholes&#34;&gt;Find Your Audience’s Watering Holes&lt;/h3&gt;&#xA;&lt;p&gt;After choosing an audience, the next step is to find their watering holes, where they hang out online. Some examples of places where Swift developers hang out online include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Twitter&lt;/li&gt;&#xA;&lt;li&gt;Reddit&lt;/li&gt;&#xA;&lt;li&gt;Slack chat rooms&lt;/li&gt;&#xA;&lt;li&gt;Stack Overflow&lt;/li&gt;&#xA;&lt;li&gt;Apple’s developer forums&lt;/li&gt;&#xA;&lt;li&gt;Mailing lists&lt;/li&gt;&#xA;&lt;li&gt;Blogs&lt;/li&gt;&#xA;&lt;li&gt;GitHub&lt;/li&gt;&#xA;&lt;li&gt;Micro.blog&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The best watering holes are places where people have discussions. That makes Reddit a better watering hole than Stack Overflow.&lt;/p&gt;&#xA;&lt;h4 id=&#34;twitter&#34;&gt;Twitter&lt;/h4&gt;&#xA;&lt;p&gt;Finding Swift developers on Twitter is going to require some searching and use of hashtags. The following are some search terms that will help you find Swift developers:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;#swiftlang&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Xcode&lt;/li&gt;&#xA;&lt;li&gt;The names of Apple frameworks, such as UIKit and Core Data&lt;/li&gt;&#xA;&lt;li&gt;The names of classes in Apple’s frameworks&lt;/li&gt;&#xA;&lt;li&gt;Apple developer conferences, such as WWDC and AltConf&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Either follow the Swift developers you find through your searches or build a list so you can see what they’re talking about on Twitter.&lt;/p&gt;&#xA;&lt;h4 id=&#34;reddit&#34;&gt;Reddit&lt;/h4&gt;&#xA;&lt;p&gt;The following Reddit groups are where Swift developers congregate:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/iOSProgramming/&#34;&gt;iOS Programming&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/swift/&#34;&gt;Swift&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/Xcode/&#34;&gt;Xcode&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/SwiftUI/&#34;&gt;SwiftUI&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/macosprogramming/&#34;&gt;Mac Programming&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;slack&#34;&gt;Slack&lt;/h4&gt;&#xA;&lt;p&gt;The following Slack chat rooms are where Swift developers congregate:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://ios-developers.slack.com/&#34;&gt;iOS Developers&lt;/a&gt; (&lt;a href=&#34;https://ios-developers.io/&#34;&gt;Invite Link&lt;/a&gt;)&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://cocoaheads.slack.com/&#34;&gt;CocoaHeads&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://hackingwithswift.slack.com/&#34;&gt;Hacking with Swift&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://appkit-abusers.slack.com/&#34;&gt;AppKit Abusers&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Slack chat rooms require an invite to join.&lt;/p&gt;&#xA;&lt;h3 id=&#34;salessafari&#34;&gt;Sales Safari&lt;/h3&gt;&#xA;&lt;p&gt;Visit the watering holes and research what people are talking about. When you find an interesting discussion, create a new text document with the URL of the discussion so you can go back to it in the future. Add sections named Pain, Jargon, and Recommendations in the text document.&lt;/p&gt;&#xA;&lt;p&gt;Write down any phrases that express pain and frustration in the Pain section. The original question will be the major source of pain.&lt;/p&gt;&#xA;&lt;p&gt;Write down any jargon in the Jargon section. Examples of jargon for Swift developers are the names of Apple’s classes and frameworks. The term massive view controller is another example. You can use the list of jargon to search the watering holes and the Internet for more discussions and data.&lt;/p&gt;&#xA;&lt;p&gt;Write down any recommendations in the Recommendations section. Many of the answers to the original question are going to be recommendations. If someone suggests doing something or avoiding something, write it down.&lt;/p&gt;&#xA;&lt;p&gt;Sales safari takes a long time to generate data, 30 hours or more. But when you gather the data you will have a better understanding of your audience and its needs. Patterns will emerge.&lt;/p&gt;&#xA;&lt;h3 id=&#34;participateinthecommunity&#34;&gt;Participate in the Community&lt;/h3&gt;&#xA;&lt;p&gt;While you do the sales safari, participate in the community to build trust. If someone asks a question that you can answer, answer the question. When people see you helping other people, they are more likely to trust you.&lt;/p&gt;&#xA;&lt;h3 id=&#34;e-bombs&#34;&gt;E-bombs&lt;/h3&gt;&#xA;&lt;p&gt;E-bombs are educational blog posts or videos. If you find multiple people asking the same question during your sales safari, answering that question is a good topic for an e-bomb.&lt;/p&gt;&#xA;&lt;p&gt;When someone asks that question in the future, you can answer the question and link to your e-bomb for more detailed information. Doing this lets you get the word out about your e-bombs without being seen as self-promoting. Answering a question with a link to your e-bomb is going to be more effective than posting links to the e-bombs on Reddit or Twitter.&lt;/p&gt;&#xA;&lt;h3 id=&#34;developasmallproduct&#34;&gt;Develop a Small Product&lt;/h3&gt;&#xA;&lt;p&gt;Once you gather data on your audience, know what they need, and build a following with e-bombs, you can start building the product. Start with a small product that you can finish in 2–3 months. If you pick something too big, you may never complete and ship the product. You’re more likely to ship a smaller product.&lt;/p&gt;&#xA;&lt;h3 id=&#34;additionalinformation&#34;&gt;Additional Information&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://stackingthebricks.com&#34;&gt;Stacking the Bricks website&lt;/a&gt; has numerous articles and podcasts on the 30×500 method. They also have a free email course.&lt;/p&gt;&#xA;&lt;p&gt;If you have two thousand dollars, you can enroll in the &lt;a href=&#34;https://30x500.com/academy/&#34;&gt;30×500 class&lt;/a&gt; that walks you step by step through the 30×500 method. They have signups every 3–4 months.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Displaying Data in a Mac Table View</title>
      <link>https://swiftdevjournal.com/displaying-data-in-a-mac-table-view/</link>
      <pubDate>Mon, 15 Jul 2019 19:08:18 +0000</pubDate>
      <guid>https://swiftdevjournal.com/displaying-data-in-a-mac-table-view/</guid>
      <description>&lt;p&gt;Displaying data in a Mac table view has the following requirements:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Data to display.&lt;/li&gt;&#xA;&lt;li&gt;Make the table view controller conform to the &lt;code&gt;NSTableViewDelegate&lt;/code&gt; and &lt;code&gt;NSTableViewDataSource&lt;/code&gt; protocols.&lt;/li&gt;&#xA;&lt;li&gt;Write the function &lt;code&gt;numberOfRows&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Write the function &lt;code&gt;viewForTableColumn&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Set the table view’s data source and delegate.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;datatodisplay&#34;&gt;Data to Display&lt;/h3&gt;&#xA;&lt;p&gt;A table view needs data to display. Usually table view data is in an array. As an example, suppose you have a note-taking app with a struct for a note.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Note&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; title: String = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; contents: String = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You will have an array of notes to display in the table view.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; notes = [Note]()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;conformtodelegateanddatasourceprotocols&#34;&gt;Conform to Delegate and Data Source Protocols&lt;/h3&gt;&#xA;&lt;p&gt;To make a Swift class or struct conform to protocols, add a colon after the name of the struct/class and add the protocol names, separated by commas. It’s similar to inheriting from a class.&lt;/p&gt;&#xA;&lt;p&gt;The following code shows how to declare a class extension for a table view controller that conforms to the required protocols, &lt;code&gt;NSTableViewDelegate&lt;/code&gt; and &lt;code&gt;NSTableViewDataSource&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extension&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TableViewController&lt;/span&gt;: NSTableViewDelegate, NSTableViewDataSource {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Place the data source and delegate functions&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// inside the extension.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;numberofrows&#34;&gt;numberOfRows&lt;/h3&gt;&#xA;&lt;p&gt;The first function you must write is &lt;code&gt;numberOfRows&lt;/code&gt;, which returns the number of rows in the table view. The number of rows is going to equal the number of items in the data source array. The following code shows an example of the &lt;code&gt;numberOfRows&lt;/code&gt; function for a note-taking app:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;numberOfRows&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; aTableView: NSTableView) -&amp;gt; Int {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; notes.count&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;viewfortablecolumn&#34;&gt;viewForTableColumn&lt;/h3&gt;&#xA;&lt;p&gt;The second function you must write is &lt;code&gt;viewForTableColumn&lt;/code&gt;, which returns the view for a table view column.&lt;/p&gt;&#xA;&lt;p&gt;Before you write code, you need to enter an identifier for the table column so you can load the cell from the storyboard. Open the storyboard, select the table column, and open the identity inspector. Enter an identifier for the column in the Identifier text field.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/TableColumnIdentifier.png&#34; alt=&#34;table column identifier&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Remember the identifier you used because you’re going to need it when you write &lt;code&gt;viewForTableColumn&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Now you can write the &lt;code&gt;viewForTableColumn&lt;/code&gt; function. The function will create the table view cell from the storyboard by calling the &lt;code&gt;NSTableView&lt;/code&gt; method &lt;code&gt;makeView&lt;/code&gt;. After creating the table view cell, set the cell’s text field contents to the data you want to display in the cell.&lt;/p&gt;&#xA;&lt;p&gt;The following code demonstrates how to display a note’s title in the table column:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tableView&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; tableView: NSTableView, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  viewFor tableColumn: NSTableColumn?, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  row: Int) -&amp;gt; NSView? {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; cellView = tableView.makeView(withIdentifier: &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    NSUserInterfaceItemIdentifier(rawValue: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TitleColumn&amp;#34;&lt;/span&gt;), &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    owner: &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? NSTableCellView &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;   &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cellView.textField?.stringValue = notes[row].title&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; cellView      &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;guard&lt;/code&gt; statement says to return nil if a user interface element with the raw value of &lt;code&gt;TitleColumn&lt;/code&gt;, the identifier you set in the storyboard, is not found in the storyboard. If the element is found, set the cell’s text field to display the title of the note at subscript &lt;code&gt;row&lt;/code&gt; in the &lt;code&gt;notes&lt;/code&gt; array, then return the cell’s view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;setthetableviewsdatasourceanddelegate&#34;&gt;Set the Table View’s Data Source and Delegate&lt;/h3&gt;&#xA;&lt;p&gt;The last step is to set the table view’s data source and delegate to the table view’s view controller. Setting the data source and delegate allows the functions &lt;code&gt;numberOfRows&lt;/code&gt; and &lt;code&gt;viewForTableColumn&lt;/code&gt; to be called when loading the table view controller.&lt;/p&gt;&#xA;&lt;p&gt;Open the storyboard and make a connection from the table view to the table view’s view controller. A HUD like the following will open:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/TableViewDelegateHUD.png&#34; alt=&#34;table view delegate&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select dataSource. Repeat the connection and select delegate.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Responding to Mac Menu Selections</title>
      <link>https://swiftdevjournal.com/responding-to-mac-menu-selections/</link>
      <pubDate>Mon, 08 Jul 2019 18:53:22 +0000</pubDate>
      <guid>https://swiftdevjournal.com/responding-to-mac-menu-selections/</guid>
      <description>&lt;p&gt;It’s not too difficult to add menus and menu items to a Mac app using Xcode’s Object Library. What can be tricky is how to get your app to respond properly when someone chooses a menu item that you added.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createanaction&#34;&gt;Create an Action&lt;/h3&gt;&#xA;&lt;p&gt;There are two steps to handling a menu selection. The first step is to create an IBAction, which is a function that will get called when someone chooses the menu item. The following code shows an example of defining an IBAction for an Export menu item:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@IBAction&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;export&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; sender: NSMenuItem) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Normally you write another function that does the actual work and call that function from the IBAction.&lt;/p&gt;&#xA;&lt;h3 id=&#34;connectthemenuitemtotheaction&#34;&gt;Connect the Menu Item to the Action&lt;/h3&gt;&#xA;&lt;p&gt;The second step is to connect the menu item to the action you created. Connecting the menu item is required to enable the menu item. If you find your menu items are disabled, make sure they’re connected.&lt;/p&gt;&#xA;&lt;p&gt;Open the storyboard and make a connection (Control-drag) from the menu item to the First Responder item in the application scene. A HUD panel with a long list of actions will open. Select your action from the list. Now your app should be responding properly to menu selections.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>An Introduction to Xcode’s Debugger</title>
      <link>https://swiftdevjournal.com/an-introduction-to-xcodes-debugger/</link>
      <pubDate>Wed, 19 Jun 2019 04:15:10 +0000</pubDate>
      <guid>https://swiftdevjournal.com/an-introduction-to-xcodes-debugger/</guid>
      <description>&lt;p&gt;I see a lot of questions on forums from iOS and Mac developers having issues with their code not working properly or crashing with cryptic error messages, like the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Thread 1: signal SIGABRT&lt;/li&gt;&#xA;&lt;li&gt;Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value&lt;/li&gt;&#xA;&lt;li&gt;EXC_CRASH (SIGTRAP)&lt;/li&gt;&#xA;&lt;li&gt;Unrecognized selector sent to instance&lt;/li&gt;&#xA;&lt;li&gt;Thread 1: EXC_BAD_ACCESS (code=2, address=0x102044190)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Many of these issues can be fixed quickly with the help of Xcode’s debugger. In this article I will show you the basics of Xcode’s debugger so you can find and fix bugs in your code more quickly.&lt;/p&gt;&#xA;&lt;h3 id=&#34;breakpoints&#34;&gt;Breakpoints&lt;/h3&gt;&#xA;&lt;p&gt;Breakpoints are fundamental to using debuggers. Breakpoints pause your app so you can debug it. If you want to debug an Xcode project, you will have to set at least one breakpoint.&lt;/p&gt;&#xA;&lt;h4 id=&#34;settingbreakpoints&#34;&gt;Setting Breakpoints&lt;/h4&gt;&#xA;&lt;p&gt;The easiest way to set a breakpoint is to click on the left side of Xcode’s editor next to the line of code where you want your app to pause.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/EnabledBreakpoint.png&#34; alt=&#34;enabled breakpoint&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The blue arrow in the editor indicates a set breakpoint.&lt;/p&gt;&#xA;&lt;h4 id=&#34;disablingbreakpoints&#34;&gt;Disabling Breakpoints&lt;/h4&gt;&#xA;&lt;p&gt;Suppose you set a breakpoint inside the loop. You don’t want your app to pause every time you go through the loop. By disabling the breakpoint after going through the loop once, Xcode won’t pause at the breakpoint until you enable it.&lt;/p&gt;&#xA;&lt;p&gt;Click on an enabled breakpoint to disable it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DisabledBreakpoint.png&#34; alt=&#34;disabled breakpoint&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;settinganexceptionbreakpoint&#34;&gt;Setting an Exception Breakpoint&lt;/h4&gt;&#xA;&lt;p&gt;Setting a breakpoint on a line of code works when you have an idea of where the problem is in your code. But if your app is crashing, it can be tough to find the source of the crash in your code.&lt;/p&gt;&#xA;&lt;p&gt;Finding the source of crashes is where exception breakpoints come in. When your app crashes, it throws an exception. Setting an exception breakpoint pauses execution of your app when it crashes so you can locate the source of the crash.&lt;/p&gt;&#xA;&lt;p&gt;To create an exception breakpoint, choose Debug &amp;gt; Breakpoints &amp;gt; Create Exception Breakpoint. A popover opens.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ExceptionBreakpointPopover.png&#34; alt=&#34;exception breakpoint&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;You shouldn’t have to change anything in the popover. Make sure the Exception menu is set to All and the Break menu is set to break on throw.&lt;/p&gt;&#xA;&lt;p&gt;You can find more information on the common causes of app crashes in the &lt;a href=&#34;https://www.swiftdevjournal.com/fixing-and-avoiding-crashes-in-swift-code/&#34;&gt;Fixing and Avoiding Crashes in Swift Code article&lt;/a&gt; on this site.&lt;/p&gt;&#xA;&lt;h3 id=&#34;debugarea&#34;&gt;Debug Area&lt;/h3&gt;&#xA;&lt;p&gt;Now that you set some breakpoints, you can build and run your project. When your app reaches a breakpoint, Xcode pauses the app, showing the debug area of the project window at the bottom of the window.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DebugAreaHighlighted.png&#34; alt=&#34;debug area&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;As you can see in the screenshot, there are three sections of the debug area.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Debug bar&lt;/li&gt;&#xA;&lt;li&gt;Variables view&lt;/li&gt;&#xA;&lt;li&gt;Console&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;debugbar&#34;&gt;Debug Bar&lt;/h4&gt;&#xA;&lt;p&gt;The debug bar contains buttons to perform the most common debugging commands. There are two sets of buttons divided by a thin vertical separator. The first set has the following buttons, running from left to right:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Show/hide the debug area&lt;/li&gt;&#xA;&lt;li&gt;Activate/deactivate breakpoints, which allows you to quickly toggle your active breakpoints with one click.&lt;/li&gt;&#xA;&lt;li&gt;Resume program execution&lt;/li&gt;&#xA;&lt;li&gt;Step over&lt;/li&gt;&#xA;&lt;li&gt;Step into&lt;/li&gt;&#xA;&lt;li&gt;Step out&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The second set has the following buttons:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Debug view hierarchy&lt;/li&gt;&#xA;&lt;li&gt;Debug memory graph&lt;/li&gt;&#xA;&lt;li&gt;Override appearance&lt;/li&gt;&#xA;&lt;li&gt;Simulate location&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The buttons in the second set are beyond the scope of this article. Debugging the view hierarchy and debugging the memory graph could be the subject of their own articles.&lt;/p&gt;&#xA;&lt;h4 id=&#34;stepping&#34;&gt;Stepping&lt;/h4&gt;&#xA;&lt;p&gt;In the previous section you saw that the debug bar has three buttons for stepping through your code: step over, step into, and step out. When should you step over, step into, and step out?&lt;/p&gt;&#xA;&lt;p&gt;You are going to step over code the most. When you step over a line of code, the debugger executes that line of code and moves to the next line. Unless the current line of code calls another function, you should step over that line.&lt;/p&gt;&#xA;&lt;p&gt;If the current line of code calls another function, you may want to step into the function. Suppose you have a function A that calls function B. If you step over the call to B, the debugger goes through all the code in B and takes you to the next line in A. This behavior may be what you want, especially if you are making a call to a function in Apple’s frameworks, where you don’t have the source code.&lt;/p&gt;&#xA;&lt;p&gt;But you may want to step through the code in B. To step through the code in B, step into the call to B in function A. The debugger will take you to the start of B, where you can step over the code in B line by line.&lt;/p&gt;&#xA;&lt;p&gt;When you step into a function, you can use the Step Out button to go back to the previous function. If you are in B and want to go back to A, click the Step Out button.&lt;/p&gt;&#xA;&lt;h4 id=&#34;variablesview&#34;&gt;Variables View&lt;/h4&gt;&#xA;&lt;p&gt;The variables view shows your app’s variables and their values. Sometimes it can be tough to find the value you want in the variables view. The variable you want may be nested inside data structures. The value may show up as a memory address instead of the real value. When the variables view doesn’t show what you want, you must resort to the console.&lt;/p&gt;&#xA;&lt;h4 id=&#34;console&#34;&gt;Console&lt;/h4&gt;&#xA;&lt;p&gt;The console shows any messages your app generates as it runs. If you have any &lt;code&gt;print&lt;/code&gt; statements in your code, the printed messages will appear in the console.&lt;/p&gt;&#xA;&lt;p&gt;You can also use the console to run LLDB debugger commands. The &lt;a href=&#34;https://lldb.llvm.org/index.html&#34;&gt;LLDB page&lt;/a&gt; has a list of commands.&lt;/p&gt;&#xA;&lt;p&gt;One common command is the &lt;code&gt;po&lt;/code&gt; command that prints out the contents of a variable. If you type a variable name, you’ll notice the console supports Xcode’s autocompletion.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Introduction to Mac Development: Connecting UI Elements</title>
      <link>https://swiftdevjournal.com/introduction-to-mac-development-connecting-ui-elements/</link>
      <pubDate>Sun, 07 Apr 2019 18:20:17 +0000</pubDate>
      <guid>https://swiftdevjournal.com/introduction-to-mac-development-connecting-ui-elements/</guid>
      <description>&lt;p&gt;If you read the Connections Inspector section of &lt;a href=&#34;https://www.swiftdevjournal.com/introduction-to-mac-development-build-the-ui/&#34;&gt;the article on how to build a user interface for a Mac app&lt;/a&gt;, you’ll notice I didn’t mention how to make connections in your user interface. Making connections is a large enough topic to warrant its own article, which you are reading now. After reading this article you’ll know how to connect UI elements so you can access them in your code.&lt;/p&gt;&#xA;&lt;p&gt;Virtually all the material in this article also applies to iOS apps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;outlets&#34;&gt;Outlets&lt;/h3&gt;&#xA;&lt;p&gt;In Interface Builder (it’s part of Xcode) you create connections by creating outlets and actions. An outlet is a variable that holds a reference to an item in a storyboard or xib file. Use outlets to access UI elements in your code.&lt;/p&gt;&#xA;&lt;h3 id=&#34;actions&#34;&gt;Actions&lt;/h3&gt;&#xA;&lt;p&gt;An action is a function that gets called when someone interacts with your app’s user interface, such as choosing a menu item or clicking a button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingandconnectinganoutlet&#34;&gt;Creating and Connecting an Outlet&lt;/h3&gt;&#xA;&lt;p&gt;Interface Builder lets you create and connect outlets and actions in one step. To create an outlet and connect it, start by opening the assistant editor. Choose Editor &amp;gt; Assistant to open the assistant editor. If you’re running an older version of Xcode, choose View &amp;gt; Assistant Editor &amp;gt; Show Assistant Editor.&lt;/p&gt;&#xA;&lt;p&gt;Have the storyboard open in one editor. Have the source code file open in the second editor for the class, most likely a view controller, where you want to add the outlet.&lt;/p&gt;&#xA;&lt;p&gt;Select the UI element in the storyboard. Hold down the Control key, and drag to the source code file. When you are inside the class, Xcode’s editor will display the message &lt;code&gt;Insert Outlet or Action&lt;/code&gt;. Release the button. A popover like the following will open:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreateOutlet.png&#34; alt=&#34;create outlet&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter the name of the outlet in the Name text field. The type is the type of the UI element you selected in the storyboard. Make sure the Storage menu is set to Strong. Click the Connect button to create the outlet and connect the UI element to the outlet.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ConnectedOutlets.png&#34; alt=&#34;connnected outlets&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Notice the filled-in circles on the left side next to each outlet. Those circles tell you the outlets are connected. Once you connect an outlet, you can access it in your code.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingandconnectinganaction&#34;&gt;Creating and Connecting an Action&lt;/h3&gt;&#xA;&lt;p&gt;Creating and connecting an action is pretty much the same as creating and connecting an outlet. Open the assistant editor so the storybord and source code file are both open. Select the UI element and control-drag to the source code file.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreateAction.png&#34; alt=&#34;create action&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter a name for the action in the Name text field. Xcode defaults to using the &lt;code&gt;Any&lt;/code&gt; type for actions, which means the sender of the action can be any data type. You can also use the type of the UI element you selected in the storyboard. Use the type of the UI element if you need to access a property of that element in the action’s code.&lt;/p&gt;&#xA;&lt;p&gt;Click the Connect button to create the action and connect the UI element to the action.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Connected-Action.png&#34; alt=&#34;connnected action&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The filled-in circle indicates the action is connected. Once you connect an action, you can add code for the action so your app responds properly to the action.&lt;/p&gt;&#xA;&lt;h3 id=&#34;exercise&#34;&gt;Exercise&lt;/h3&gt;&#xA;&lt;p&gt;Create an app that keeps track of the number of times someone clicks a button. In the user interface, add a button and two labels: one with the text &lt;code&gt;Clicks:&lt;/code&gt; and one with the initial value of zero.&lt;/p&gt;&#xA;&lt;p&gt;Add an outlet for the label that displays the number of clicks. Add an action to handle the button click, which involves increasing the number of clicks by one and displaying the current number of clicks in the label. I &lt;a href=&#34;https://github.com/SwiftDevJournal/ButtonClickCounter&#34;&gt;have the project on GitHub&lt;/a&gt; for you to look at if you get stuck.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Introduction to Mac Development: Build the UI</title>
      <link>https://swiftdevjournal.com/introduction-to-mac-development-build-the-ui/</link>
      <pubDate>Fri, 05 Apr 2019 18:03:13 +0000</pubDate>
      <guid>https://swiftdevjournal.com/introduction-to-mac-development-build-the-ui/</guid>
      <description>&lt;p&gt;After creating a project, the next step in developing a Mac app is to build the user interface. In this article you’ll learn the basics of building user interfaces with Interface Builder, which is a part of Xcode.&lt;/p&gt;&#xA;&lt;p&gt;I talk about storyboards in this article, but most of the material applies to xib files as well. The main differences are that xib files do not have scenes and do not have view controllers.&lt;/p&gt;&#xA;&lt;h3 id=&#34;openthestoryboard&#34;&gt;Open the Storyboard&lt;/h3&gt;&#xA;&lt;p&gt;Select the &lt;code&gt;main.storyboard&lt;/code&gt; file to open it in Xcode. The following screenshot shows what a storyboard looks like initially:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/InitialStoryboardLabeled.png&#34; alt=&#34;initial storyboard&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The left side of the storyboard (or xib file) contains the document outline, which shows the items in the storyboard. The right side of the storyboard contains the canvas, which is where you lay out the user interface.&lt;/p&gt;&#xA;&lt;p&gt;A basic storyboard in a Mac app has the following scenes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Application scene&lt;/li&gt;&#xA;&lt;li&gt;Window controller scene&lt;/li&gt;&#xA;&lt;li&gt;View controller scene&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The application scene contains the menu bar. The window controller scene contains the main window for the app. The view controller scene contains the view controller that manages the window’s content. You place the controls in your user interface in the view controller.&lt;/p&gt;&#xA;&lt;p&gt;Simple user interfaces can get away with one window controller and one view controller. More complex user interfaces require more scenes. If you were going to recreate the interface for Apple’s Mail app, you would need four view controller scenes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A view controller for the outline view with the list of mailboxes and folders.&lt;/li&gt;&#xA;&lt;li&gt;A view controller for the table view containing the messages in the selected mailbox or folder.&lt;/li&gt;&#xA;&lt;li&gt;A view controller for the text view showing the contents of the selected message.&lt;/li&gt;&#xA;&lt;li&gt;A split view controller to contain the three view controllers.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;A Mac app with user preferences would have a window controller scene for the preferences window.&lt;/p&gt;&#xA;&lt;h3 id=&#34;findingtheuielements&#34;&gt;Finding the UI Elements&lt;/h3&gt;&#xA;&lt;p&gt;To build a user interface you must first find the user interface elements. The user interface elements are in the object library. In Xcode 10 Apple changed the location of the object library so it can be difficult to find. The Library button is on the right side of the toolbar at the top of the project window.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode10ObjectLibraryHighlighted.png&#34; alt=&#34;object library&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Newer versions of Xcode have an Add (+) button to open the object library.&lt;/p&gt;&#xA;&lt;p&gt;Click the Library button to open the object library. Option-clicking the Library button keeps the object library open until you explicitly close it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ObjectLibraryWindow.png&#34; alt=&#34;object library window&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;At the top of the object library window is a search field. Enter a search term to more easily find an item in the object library. If you enter &lt;code&gt;button&lt;/code&gt; in the search field, the object library shows all the available buttons.&lt;/p&gt;&#xA;&lt;h3 id=&#34;adduielementstoyourinterface&#34;&gt;Add UI Elements to Your Interface&lt;/h3&gt;&#xA;&lt;p&gt;To add an element to your app’s user interface, select it from the object library and drag it to the canvas. For most visible controls, including labels and buttons, you should drag the control to a view controller in the canvas.&lt;/p&gt;&#xA;&lt;h3 id=&#34;movingandresizingelements&#34;&gt;Moving and Resizing Elements&lt;/h3&gt;&#xA;&lt;p&gt;Select a UI element from the canvas or document outline to move or resize it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SelectedItem.png&#34; alt=&#34;selected item&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;To move an element, select it and drag it to where you want it to be. To resize an element, select it, click one of the squares on the edges of the selected element, and drag.&lt;/p&gt;&#xA;&lt;h3 id=&#34;makingotherchanges&#34;&gt;Making Other Changes&lt;/h3&gt;&#xA;&lt;p&gt;To make other changes to UI elements, use the inspectors on the right side of the project window. If you don’t see the inspector, either choose View &amp;gt; Inspectors &amp;gt; Show X Inspector, where X is the name of the inspector or click the button in the upper right corner of the project window.&lt;/p&gt;&#xA;&lt;p&gt;Xcode has the following inspectors for Mac UI elements:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Identity inspector&lt;/li&gt;&#xA;&lt;li&gt;Attributes inspector&lt;/li&gt;&#xA;&lt;li&gt;Size inspector&lt;/li&gt;&#xA;&lt;li&gt;Connections inspector&lt;/li&gt;&#xA;&lt;li&gt;Bindings inspector&lt;/li&gt;&#xA;&lt;li&gt;View effects inspector&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The attributes inspector is the inspector you’ll use the most.&lt;/p&gt;&#xA;&lt;h4 id=&#34;identityinspector&#34;&gt;Identity Inspector&lt;/h4&gt;&#xA;&lt;p&gt;The thing you’ll use the identity inspector for most is setting the class of a UI element.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/IdentityInspector.png&#34; alt=&#34;identity inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Set the class for a UI element if you create a subclass of one of Apple’s classes. Set the class to tell Xcode that the UI element is your subclass. View controllers are what you’re most likely to subclass.&lt;/p&gt;&#xA;&lt;h4 id=&#34;attributesinspector&#34;&gt;Attributes Inspector&lt;/h4&gt;&#xA;&lt;p&gt;The attributes inspector is where you view and edit a UI element’s attributes. What you can set in the attributes inspector depends on the UI element. The following screenshot shows the attributes inspector for a button:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/AttributesInspector.png&#34; alt=&#34;attributes inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;As you can see there are a lot of attributes you can set for a button.&lt;/p&gt;&#xA;&lt;h4 id=&#34;sizeinspector&#34;&gt;Size Inspector&lt;/h4&gt;&#xA;&lt;p&gt;The size inspector is where you can see and change a UI element’s position and size.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/IdentityInspector.png&#34; alt=&#34;identity inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you are not using auto layout, use the Autoresizing mask to determine how the element’s size and position changes when someone resizes the window.&lt;/p&gt;&#xA;&lt;h4 id=&#34;connectionsinspector&#34;&gt;Connections Inspector&lt;/h4&gt;&#xA;&lt;p&gt;The connections inspector shows the connections a UI element has and can have.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ConnectionsInspector.png&#34; alt=&#34;connections inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The Sent Actions section in the screenshot shows an actual connection along with the &lt;code&gt;button&lt;/code&gt; outlet in the Referencing Outlets section. The rest of the items in the screenshot are the possible connections that element can have.&lt;/p&gt;&#xA;&lt;p&gt;Click the X on a connection to remove the connection.&lt;/p&gt;&#xA;&lt;h4 id=&#34;bindingsinspector&#34;&gt;Bindings Inspector&lt;/h4&gt;&#xA;&lt;p&gt;The bindings inspector works with Cocoa bindings. Cocoa bindings are not available on iOS and have not been changed since macOS 10.5 so you’re not going to find a lot of current information on how to use them.&lt;/p&gt;&#xA;&lt;p&gt;Cocoa bindings use special controllers to keep user interface elements and data objects in sync. If you open the object library and enter &lt;code&gt;Controller&lt;/code&gt; in the search field, you can see the bindings-compatible controllers: object controller, array controller, dictionary controller, tree controller, and user defaults controller.&lt;/p&gt;&#xA;&lt;p&gt;To use bindings add one of the bindings-compatible controllers to the storyboard or xib file. Use the attributes inspector to determine the type of data the controller manages. Use the bindings inspector to bind a UI element to the controller.&lt;/p&gt;&#xA;&lt;p&gt;The bindings inspector shows all the bindings a UI element has.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/BindingsInspector.png&#34; alt=&#34;bindings inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;You can bind a UI element by selecting the Bind to checkbox, choosing a controller to bind to, and supplying the appropriate keys.&lt;/p&gt;&#xA;&lt;h4 id=&#34;vieweffectsinspector&#34;&gt;View Effects Inspector&lt;/h4&gt;&#xA;&lt;p&gt;The view effects inspector works with Core Animation to animate UI elements.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ViewEffectsInspector.png&#34; alt=&#34;view effects inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;exercise&#34;&gt;Exercise&lt;/h3&gt;&#xA;&lt;p&gt;Add some controls to a storyboard. Run the project and see those controls in the window.&lt;/p&gt;&#xA;&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;&#xA;&lt;p&gt;Remember the following points to build your Mac app’s user interface:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Select the storyboard or xib file in the project navigator to open it.&lt;/li&gt;&#xA;&lt;li&gt;Option-click the Library button to access the UI elements.&lt;/li&gt;&#xA;&lt;li&gt;Drag a UI element from the object library to the canvas to add it to the user interface.&lt;/li&gt;&#xA;&lt;li&gt;Use the inspectors to make changes to the elements.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Introduction to Mac Development: Create a Project</title>
      <link>https://swiftdevjournal.com/introduction-to-mac-development-create-a-project/</link>
      <pubDate>Mon, 25 Mar 2019 19:25:21 +0000</pubDate>
      <guid>https://swiftdevjournal.com/introduction-to-mac-development-create-a-project/</guid>
      <description>&lt;p&gt;The first step in creating a Mac app is to create a project in Xcode. This article walks you through creating a Mac app project and explains the files Xcode creates for the project.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingtheproject&#34;&gt;Creating the Project&lt;/h3&gt;&#xA;&lt;p&gt;Choose File &amp;gt; New &amp;gt; Project to create a new project. The New Project Assistant window opens.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/NewProjectStep1.png&#34; alt=&#34;new project step 1&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select macOS from the top of the window to show the Mac project templates. Select Cocoa App from the list of application project templates. Click the Next button.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/NewProjectStep2.png&#34; alt=&#34;new project step 2&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Now things become a little more complicated. You must supply the following information for the new project so Apple can set the project the way you want:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Product name&lt;/li&gt;&#xA;&lt;li&gt;Team&lt;/li&gt;&#xA;&lt;li&gt;Organization name&lt;/li&gt;&#xA;&lt;li&gt;Organization identifier&lt;/li&gt;&#xA;&lt;li&gt;Language&lt;/li&gt;&#xA;&lt;li&gt;Whether to use storyboards or xib files for the user interface&lt;/li&gt;&#xA;&lt;li&gt;Whether or not to create a document-based app&lt;/li&gt;&#xA;&lt;li&gt;Whether or not to use Core Data&lt;/li&gt;&#xA;&lt;li&gt;Whether or not to add testing targets&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;productname&#34;&gt;Product Name&lt;/h4&gt;&#xA;&lt;p&gt;The product name is the name of the project. It’s also the name of the application. The menu bar for the app will have a menu with the product name that has menu items to quit and hide the app that use the product name.&lt;/p&gt;&#xA;&lt;p&gt;It is possible to rename a project after creating it. But choosing a good name for the project when you create it makes things easier.&lt;/p&gt;&#xA;&lt;h4 id=&#34;team&#34;&gt;Team&lt;/h4&gt;&#xA;&lt;p&gt;The Team menu is for people who have a paid Apple developer account. Choose your team from the menu, and Xcode will use it to code sign your app. If you don’t have a paid developer account, choose None from the Team menu.&lt;/p&gt;&#xA;&lt;h4 id=&#34;organizationname&#34;&gt;Organization Name&lt;/h4&gt;&#xA;&lt;p&gt;The organization name appears in the copyright notice of the source code files you create for your project. If you don’t have an organization name, use your name.&lt;/p&gt;&#xA;&lt;h4 id=&#34;organizationidentifier&#34;&gt;Organization Identifier&lt;/h4&gt;&#xA;&lt;p&gt;The organization identifier uniquely identifies the organization. The identifier takes the form &lt;code&gt;com.OrganizationName&lt;/code&gt;. There should be no spaces in the organization identifier.&lt;/p&gt;&#xA;&lt;h4 id=&#34;language&#34;&gt;Language&lt;/h4&gt;&#xA;&lt;p&gt;The Language menu determines the programming language for the source code files Xcode creates for the project. There are two language choices for Mac apps: Swift and Objective-C.&lt;/p&gt;&#xA;&lt;h4 id=&#34;storyboardsorxibfiles&#34;&gt;Storyboards or Xib Files&lt;/h4&gt;&#xA;&lt;p&gt;The Use Storyboards checkbox determines whether Xcode creates a storyboard or a xib file for your project’s user interface. Storyboards let you see the app’s entire user interface in one place. Storyboards also make working with view controllers easier. But xib files make creating master-detail interfaces easier.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Xcode 11 Update&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Xcode 11 replaces the Use Storyboards checkbox with a User Interface menu item. For a Mac app the user interface options are SwiftUI, Storyboards, and Xib Files.&lt;/p&gt;&#xA;&lt;h4 id=&#34;document-basedapps&#34;&gt;Document-based Apps&lt;/h4&gt;&#xA;&lt;p&gt;The Create Document-Based Application checkbox determines whether your app uses Apple’s document architecture. Document-based apps let people create, open, and save documents as separate files that they can share with other people. Examples of document-based apps include text editors, spreadsheets, and drawing apps.&lt;/p&gt;&#xA;&lt;p&gt;If you decide to create a document-based app, use the Document Extension text field to supply the file extension for the document files your app creates.&lt;/p&gt;&#xA;&lt;h4 id=&#34;coredata&#34;&gt;Core Data&lt;/h4&gt;&#xA;&lt;p&gt;The Use Core Data checkbox determines whether your app uses Core Data for your app’s data. Core Data is a complex technology so I recommend not using it when starting out making Mac apps.&lt;/p&gt;&#xA;&lt;h4 id=&#34;testingtargets&#34;&gt;Testing Targets&lt;/h4&gt;&#xA;&lt;p&gt;The Include Unit Tests and Include UI tests checkboxes determine whether Xcode creates targets for unit testing your app’s code and testing your app’s user interface. If you’re learning Mac development, you can deselect the checkboxes. When you start making more complex apps, unit testing and UI testing can help you write better code and design better user interfaces.&lt;/p&gt;&#xA;&lt;h3 id=&#34;finishingcreatingtheproject&#34;&gt;Finishing Creating the Project&lt;/h3&gt;&#xA;&lt;p&gt;When you supply all the information Xcode demands for the project and click the Next button, the last step is to choose a location to save your project. At the bottom of the Save panel you should see the following controls:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/NewProjectStep3.png&#34; alt=&#34;new project step 3&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you select the Create Git repository on my Mac checkbox, Xcode will place your project under version control. You can get away with not using version control for small projects. If you write an app you want to share with the public, I recommend using version control so you can track changes to files and go back to earlier versions of files if you make mistakes. I wrote &lt;a href=&#34;https://www.meandmark.com/versioncontrolbook.html&#34;&gt;a book on version control for Mac developers&lt;/a&gt; if you want to learn more about version control.&lt;/p&gt;&#xA;&lt;h3 id=&#34;projectfiles&#34;&gt;Project Files&lt;/h3&gt;&#xA;&lt;p&gt;The project navigator on the left side of the project window lists the files in your project. The following screenshot shows the files Xcode creates for a Mac project that uses Swift, uses storyboards, is not document-based, and does not use Core Data:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ProjectNavigatorAtStart.png&#34; alt=&#34;project navigator&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The files in the project name folder (ButtonClickCounter in the screenshot) are the most interesting.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;AppDelegate.swift&lt;/li&gt;&#xA;&lt;li&gt;ViewController.swift&lt;/li&gt;&#xA;&lt;li&gt;Assets.xcassets&lt;/li&gt;&#xA;&lt;li&gt;Main.storyboard&lt;/li&gt;&#xA;&lt;li&gt;Info.plist&lt;/li&gt;&#xA;&lt;li&gt;ProjectName.entitlements&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;When you’re starting Mac development, focus on the source code and storyboard files. You’ll use the other files and folders when you get closer to shipping an app.&lt;/p&gt;&#xA;&lt;p&gt;Select a file from the project navigator to open it in Xcode’s editor.&lt;/p&gt;&#xA;&lt;h4 id=&#34;appdelegate&#34;&gt;AppDelegate&lt;/h4&gt;&#xA;&lt;p&gt;The &lt;code&gt;AppDelegate.swift&lt;/code&gt; file lets you add code to run when your app launches and terminates.&lt;/p&gt;&#xA;&lt;h4 id=&#34;viewcontroller&#34;&gt;ViewController&lt;/h4&gt;&#xA;&lt;p&gt;The &lt;code&gt;ViewController.swift&lt;/code&gt; file contains a class file for the view controller Xcode creates in the storyboard. A view controller manages a view. You will create a view controller class for every view controller you add to the storyboard.&lt;/p&gt;&#xA;&lt;p&gt;Projects that use xib files instead of storyboards do not have a view controller source code file.&lt;/p&gt;&#xA;&lt;h4 id=&#34;assetsfolder&#34;&gt;Assets Folder&lt;/h4&gt;&#xA;&lt;p&gt;The Assets folder contains the images in your project. The most common use of the Assets folder is to add an icon for your app.&lt;/p&gt;&#xA;&lt;h4 id=&#34;storyboard&#34;&gt;Storyboard&lt;/h4&gt;&#xA;&lt;p&gt;The storyboard contains your app’s user interface. Select the storyboard to open it and build your app’s user interface.&lt;/p&gt;&#xA;&lt;h4 id=&#34;info.plist&#34;&gt;Info.plist&lt;/h4&gt;&#xA;&lt;p&gt;The &lt;code&gt;Info.plist&lt;/code&gt; file contains information about your app, such as a copyright notice.&lt;/p&gt;&#xA;&lt;p&gt;While you can edit the &lt;code&gt;Info.plist&lt;/code&gt; file directly, it’s usually easier to use Xcode’s project editor. Select the project (it’s the first item) from the project navigator to open the project editor. Select the app target from the left side of the project editor. Click the Info button at the top of the project editor to start editing &lt;code&gt;Info.plist&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/EditingInfoPlist.png&#34; alt=&#34;editing info.plist&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;entitlementsfile&#34;&gt;Entitlements File&lt;/h4&gt;&#xA;&lt;p&gt;The entitlements file contains a list of Apple technology capabilities that your app supports. If you select the entitlements file, you will notice that the App Sandbox is turned on.&lt;/p&gt;&#xA;&lt;p&gt;While you can add and remove capabilities from the entitlements file, it’s usually easier to do it from Xcode’s project editor. Select the app target from the left side of the project editor. Click the Capabilities button at the top of the project editor.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ProjectCapabilities.png&#34; alt=&#34;project capabilities&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you want your app to support things like iCloud and push notifications, turn the switch from Off to On. Keep in mind that most of the capabilities require your app to be code signed, which means you have to be a paid member of Apple’s developer program.&lt;/p&gt;&#xA;&lt;h3 id=&#34;exercise1:runtheproject&#34;&gt;Exercise 1: Run the Project&lt;/h3&gt;&#xA;&lt;p&gt;Choose Product &amp;gt; Run in Xcode or click the Run button in the upper left corner of the project window to run the project. An empty window should appear.&lt;/p&gt;&#xA;&lt;h3 id=&#34;exercise2:experimentwithprojectoptions&#34;&gt;Exercise 2: Experiment with Project Options&lt;/h3&gt;&#xA;&lt;p&gt;Create different types of projects and compare the files that are created. Create a project that doesn’t use storyboards. Create a document-based app project. Create a project that uses Core Data.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Resources for Learning Mac Development</title>
      <link>https://swiftdevjournal.com/resources-for-learning-mac-development/</link>
      <pubDate>Tue, 05 Mar 2019 19:42:05 +0000</pubDate>
      <guid>https://swiftdevjournal.com/resources-for-learning-mac-development/</guid>
      <description>&lt;p&gt;Last update: December 2025&lt;/p&gt;&#xA;&lt;p&gt;I’ve seen a lot of questions from people on Reddit and Slack looking for resources on Mac development in Swift. Compared to iOS development there are relatively few resources for learning to write Mac apps in Swift. I’ve collected what I found and am sharing with you.&lt;/p&gt;&#xA;&lt;h3 id=&#34;books&#34;&gt;Books and Courses&lt;/h3&gt;&#xA;&lt;p&gt;The book &lt;a href=&#34;https://www.hackingwithswift.com/store/hacking-with-macos&#34;&gt;Hacking with macOS&lt;/a&gt; teaches Mac development by building 18 projects.&lt;/p&gt;&#xA;&lt;p&gt;TrozWare publishes the book &lt;a href=&#34;https://troz.net/books/macos_tutorials/&#34;&gt;macOS by Tutorials&lt;/a&gt;, where you build two SwiftUI apps and a menu bar app with AppKit. This book is geared towards iOS developers who want to learn how to make Mac apps.&lt;/p&gt;&#xA;&lt;p&gt;If you’re completely new to Mac development, Kodeco has the book &lt;a href=&#34;https://www.kodeco.com/books/macos-apprentice/v1.0&#34;&gt;macOS Apprentice&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I wrote an introductory book on Mac development, &lt;a href=&#34;https://www.swiftdevjournal.com/swift-dev-journal-intro-to-cocoa/&#34;&gt;Swift Dev Journal’s Intro to Cocoa&lt;/a&gt;. The book walks you through the creation of a complete Mac app using AppKit, Swift, and storyboards.&lt;/p&gt;&#xA;&lt;p&gt;The book &lt;a href=&#34;https://www.amazon.com/Cocoa-Programming-OS-Ranch-Guides/dp/0134076958/&#34;&gt;Cocoa Programming for Mac OS X&lt;/a&gt; is the only other Mac programming book I see people recommend online. The book uses Swift 1.2 so a lot of the code is not going to compile with recent versions of Swift and Xcode. If you can work around that limitation, the book does do a good job of introducing Mac development with Cocoa.&lt;/p&gt;&#xA;&lt;p&gt;Mohammad Azam has the course &lt;a href=&#34;https://www.udemy.com/course/programming-macos-using-swiftui-project-based-learning/&#34;&gt;Programming macOS Using SwiftUI – Project Based Learning&lt;/a&gt; that teaches Mac development with SwiftUI.&lt;/p&gt;&#xA;&lt;p&gt;The book &lt;a href=&#34;https://leanpub.com/macos-apps-swiftui&#34;&gt;Building macOS Apps With SwiftUI: A Practical Learning Guide&lt;/a&gt; by Grace Huang covers Mac development with SwiftUI.&lt;/p&gt;&#xA;&lt;p&gt;The course &lt;a href=&#34;https://school.swiftyplace.com/courses/macos-development&#34;&gt;Build That MacOS App&lt;/a&gt; teaches Mac development with SwiftUI.&lt;/p&gt;&#xA;&lt;p&gt;Christian Tietze has a book that covers a different aspect of Mac development, &lt;a href=&#34;https://christiantietze.de/books/make-money-outside-mac-app-store-fastspring/&#34;&gt;Make Money Outside the Mac App Store&lt;/a&gt;. The book shows you how to sell Mac apps without using the Mac App Store.&lt;/p&gt;&#xA;&lt;h3 id=&#34;websites&#34;&gt;Websites&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.kodeco.com&#34;&gt;Kodeco (formerly raywenderlich.com)&lt;/a&gt; has the largest &lt;a href=&#34;https://www.kodeco.com/macos&#34;&gt;collection of modern tutorials on Mac development&lt;/a&gt;. They stopped making Mac tutorials so some tutorials may be slightly out of date.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.appcoda.com&#34;&gt;AppCoda&lt;/a&gt; has several Mac programming tutorials.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/&#34;&gt;The site you’re currently reading&lt;/a&gt; has a small but growing collection of articles on Mac development, including SwiftUI articles.&lt;/p&gt;&#xA;&lt;p&gt;If you prefer videos, &lt;a href=&#34;https://www.youtube.com/AppleProgramming&#34;&gt;Lucas Derraugh has a YouTube channel&lt;/a&gt; with videos on Mac development.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://troz.net&#34;&gt;TrozWare&lt;/a&gt; has articles on making SwiftUI Mac apps.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://nilcoalescing.com/blog&#34;&gt;Nil Coalescing blog&lt;/a&gt; has a collection of SwiftUI articles, some of which cover Mac development.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://serialcoder.dev&#34;&gt;SerialCoder.dev&lt;/a&gt; has tutorials on Mac and SwiftUI development.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://christiantietze.de/posts/&#34;&gt;Christian Tietze&lt;/a&gt; blogs about Mac app development.&lt;/p&gt;&#xA;&lt;h3 id=&#34;placestoaskquestions&#34;&gt;Places to Ask Questions&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/tagged/cocoa&#34;&gt;Stack Overflow&lt;/a&gt;. Use the &lt;code&gt;cocoa&lt;/code&gt; tag when asking Mac programming questions that aren’t about SwiftUI.&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://developer.apple.com/forums&#34;&gt;Apple’s developer forums&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/swiftui/&#34;&gt;SwiftUI Reddit group&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://forums.macrumors.com/forums/apple-programming.135&#34;&gt;MacRumors forums&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;slackworkspaces&#34;&gt;Slack Workspaces&lt;/h3&gt;&#xA;&lt;p&gt;The following workspaces on Slack are places where people talk about Mac development:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://appkit-abusers.slack.com&#34;&gt;AppKit Abusers&lt;/a&gt; is the most active Slack room for Mac development.&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://hackingwithswift.slack.com&#34;&gt;Hacking with Swift&lt;/a&gt; has a Mac development room.&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://cocoaheads.slack.com/join/shared_invite/zt-p9iytp3l-5jXJmcR__7301oJekhKsyg#/shared-invite/email&#34;&gt;CocoaHeads&lt;/a&gt; doesn’t get a lot of Mac development discussion, but the workspace covers both iOS and Mac development.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;havearesourcetoadd&#34;&gt;Have a Resource to Add?&lt;/h3&gt;&#xA;&lt;p&gt;Use the &lt;a href=&#34;https://swiftdevjournal.com/contact/&#34;&gt;Contact page&lt;/a&gt; to send me an email with your resource for learning Mac development.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Adding Folders of Files to Xcode Projects</title>
      <link>https://swiftdevjournal.com/adding-folders-of-files-to-xcode-projects/</link>
      <pubDate>Mon, 25 Feb 2019 05:04:25 +0000</pubDate>
      <guid>https://swiftdevjournal.com/adding-folders-of-files-to-xcode-projects/</guid>
      <description>&lt;p&gt;When you add a folder of files to an Xcode project by choosing File &amp;gt; Add Files to “ProjectName”, you should see the following options at the bottom of the Open panel:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode10AddFolders.png&#34; alt=&#34;add folders&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;As you can see there are two options for adding folders to a project.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create groups&lt;/li&gt;&#xA;&lt;li&gt;Create folder references&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;What’s the difference between creating groups and folder references?&lt;/p&gt;&#xA;&lt;p&gt;When you create a group for a folder, Xcode creates a gray folder (yellow folder in earlier Xcode versions) for the folder in the project navigator. Create a group when you need to edit the folder’s files in Xcode. If you’re adding a folder of source code files, you should create a group for the folder.&lt;/p&gt;&#xA;&lt;p&gt;When you create a folder reference, Xcode creates a blue folder in the project navigator. The folder will also be copied to the app bundle when you build the project. Create a folder reference when you don’t need to edit the folder’s files in Xcode. If you’re adding a folder of image or sound files, you should create a folder reference.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>I have a great idea for an app. How do I get started?</title>
      <link>https://swiftdevjournal.com/i-have-a-great-idea-for-an-app-how-do-i-get-started/</link>
      <pubDate>Mon, 11 Feb 2019 19:31:20 +0000</pubDate>
      <guid>https://swiftdevjournal.com/i-have-a-great-idea-for-an-app-how-do-i-get-started/</guid>
      <description>&lt;p&gt;I see this question come up a lot. Someone has an idea for an iOS app, and they want to know how to get started making the app. You have two options for making an iOS app: hiring a developer to make the app or making the app yourself.&lt;/p&gt;&#xA;&lt;h3 id=&#34;hireadevelopertowritetheappforyou&#34;&gt;Hire a Developer to Write the App for You&lt;/h3&gt;&#xA;&lt;p&gt;Hiring a developer is expensive. A good iOS developer charges $100(US) or more per hour. If you can afford to hire a developer, you can find one at &lt;a href=&#34;https://iosdevdirectory.com&#34;&gt;iOS Dev Directory&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;You may think you can hire someone to write an iOS app for a percentage of the profits. Unless you have a friend who’s an iOS developer, you’re going to have a tough time finding someone to work for a percentage of the profits. Working for a percentage of the profits is basically working for free because the chances of making lots of money from an iOS app are slim. Most people are unwilling to work for free.&lt;/p&gt;&#xA;&lt;h3 id=&#34;learnprogramming&#34;&gt;Learn Programming&lt;/h3&gt;&#xA;&lt;p&gt;The cheaper, more time consuming option is to make the app yourself. If you’re asking how to make an iOS app, chances are high you have never programmed before. Learning to program is the first step in making an iOS app. Trying to develop an iOS app without knowing how to program is like trying to write a book without knowing how to write. It’s going to be very difficult.&lt;/p&gt;&#xA;&lt;p&gt;Swift is the language to learn to develop iOS apps. Get a book to learn Swift. People recommend the following books to learn Swift:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.hackingwithswift.com&#34;&gt;Hacking with Swift&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.bignerdranch.com/books/swift-programming/&#34;&gt;Big Nerd Ranch’s Swift book&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://store.raywenderlich.com/products/swift-apprentice&#34;&gt;Ray Wenderlich’s Swift Apprentice book&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Despite Apple’s claims, Swift is not an easy language to learn. If you struggle learning Swift, I recommend learning Python and going back to learn Swift. Python is an easier language to learn than Swift. Once you learn Python or another programming language, learning Swift will be easier.&lt;/p&gt;&#xA;&lt;h3 id=&#34;learniosdevelopment&#34;&gt;Learn iOS Development&lt;/h3&gt;&#xA;&lt;p&gt;Once you learn how to program, you can move on to learning iOS development. My &lt;a href=&#34;https://swiftdevjournal.com/learning-ios-development/&#34;&gt;Learning iOS Development article&lt;/a&gt; has many resources for learning how to make iOS apps.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Fixing and Avoiding Crashes in Swift Code</title>
      <link>https://swiftdevjournal.com/fixing-and-avoiding-crashes-in-swift-code/</link>
      <pubDate>Tue, 05 Feb 2019 19:54:48 +0000</pubDate>
      <guid>https://swiftdevjournal.com/fixing-and-avoiding-crashes-in-swift-code/</guid>
      <description>&lt;p&gt;When you start out developing iOS or Mac apps in Swift, you run into a common problem. Your project builds without any errors but crashes when you run it. It’s frustrating to have your code not work, and the cryptic messages Xcode spews don’t help much.&lt;/p&gt;&#xA;&lt;p&gt;In this article you’ll learn how to get Xcode to show you where the crash occurs in your code. You’ll also learn the most common causes of crashes in Swift apps and how to avoid them.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addanexceptionbreakpointtolocatethecrash&#34;&gt;Add an Exception Breakpoint to Locate the Crash&lt;/h3&gt;&#xA;&lt;p&gt;Adding an exception breakpoint in Xcode makes it easy to find where your code crashes. Open Xcode’s breakpoint navigator by choosing View &amp;gt; Navigators &amp;gt; Show Breakpoint Navigator.&lt;/p&gt;&#xA;&lt;!-- raw HTML omitted --&gt;&#xA;&lt;p&gt;Click the Add (+) button at the bottom of the breakpoint navigator and choose Exception Breakpoint. A popover opens for the breakpoint.&lt;/p&gt;&#xA;&lt;!-- raw HTML omitted --&gt;&#xA;&lt;p&gt;Make sure the Exception menu is set to break on all exceptions and to break when an exception is thrown.&lt;/p&gt;&#xA;&lt;p&gt;Now when your app crashes, Xcode breaks into the debugger and shows you the line of code where the crash occurred. Showing the line of code where the crash occurred comes in handy when you’re trying to figure why your app crashed.&lt;/p&gt;&#xA;&lt;p&gt;If you look at the screenshot of the breakpoint navigator, you will notice the exception breakpoint is in the User section. User breakpoints apply to all projects so you don’t have to set them for each project.&lt;/p&gt;&#xA;&lt;p&gt;Because exception breakpoints help so much to find where your apps crash, they’re strong candidates to be user breakpoints. To make a breakpoint a user breakpoint, select it in the breakpoint navigator, control-click, and choose Move Breakpoint To &amp;gt; User. Now the exception breakpoint will fire when any of your projects crash.&lt;/p&gt;&#xA;&lt;h3 id=&#34;commoncrashcauses&#34;&gt;Common Crash Causes&lt;/h3&gt;&#xA;&lt;p&gt;Now that you can determine where your app crashes, you want to know why your code is crashing and how to fix it. Without seeing your code, I can’t tell you exactly why your code is crashing, but I can tell you the most common causes of crashes.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Unwrapping a nil Swift optional&lt;/li&gt;&#xA;&lt;li&gt;Disconnected outlets&lt;/li&gt;&#xA;&lt;li&gt;Accessing an element outside an array’s bounds&lt;/li&gt;&#xA;&lt;li&gt;Accessing an uninitialized variable&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;unwrappinganiloptional&#34;&gt;Unwrapping a Nil Optional&lt;/h4&gt;&#xA;&lt;p&gt;The leading cause of crashes in Swift apps is unwrapping a nil optional value. When you unwrap a nil optional value, you will see the following error message in Xcode’s debug console:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Fatal error: Unexpectedly found nil while unwrapping an Optional value&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This error is usually caused by two things. First, force unwrapping an optional by adding an exclamation point to a variable’s name. Second, using &lt;code&gt;as!&lt;/code&gt; to downcast an optional value to a specific type.&lt;/p&gt;&#xA;&lt;p&gt;The fix is to avoid force unwrapping. Use &lt;code&gt;if let&lt;/code&gt; or &lt;code&gt;guard&lt;/code&gt; statements to safely unwrap your optionals. Use &lt;code&gt;as?&lt;/code&gt; instead of &lt;code&gt;as!&lt;/code&gt; when downcasting. The following articles provide more detailed information on optionals:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://swiftdevjournal.com/crashing-with-swift-optionals/&#34;&gt;Crashing with Swift Optionals&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://swiftdevjournal.com/swift-optionals/&#34;&gt;Swift Optionals&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;disconnectedoutlets&#34;&gt;Disconnected Outlets&lt;/h4&gt;&#xA;&lt;p&gt;The second most common cause of crashes in Swift apps is having a disconnected outlet for a user interface element and accessing that outlet in your code.&lt;/p&gt;&#xA;&lt;p&gt;You can check if an outlet is connected in Xcode’s source code editor. Next to an outlet is a circle. The following screenshot shows a disconnected outlet:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DisconnectedOutletHighlighted.png&#34; alt=&#34;disconnected outlet&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;A connected outlet has the circle filled in.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ConnectedOutlets.png&#34; alt=&#34;connected outlet&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;To connect the outlet open Xcode’s assistant editor so the storyboard and the source code file are both open. Select the user interface element in the storyboard. Hold down the Control key and drag to the outlet in the source code file.&lt;/p&gt;&#xA;&lt;h4 id=&#34;outofrangearrayaccess&#34;&gt;Out of Range Array Access&lt;/h4&gt;&#xA;&lt;p&gt;If you try to access an element in an array that is not in the array’s range, your app will crash. Out of range errors are usually off-by–1 errors because array indices start at 0 instead of 1. An array with 10 elements has indices 0–9, not 1–10. If you try to access the tenth element with the following code:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;myArray[&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The app will crash with an out of range error because the subscript &lt;code&gt;[10]&lt;/code&gt; references the 11th member of an array with only 10 elements.&lt;/p&gt;&#xA;&lt;p&gt;You can also get an out of range error if you try to access elements in an empty array. An empty array has no elements so any subscript is out of range. Swift arrays have an &lt;code&gt;isEmpty&lt;/code&gt; property you can check to see if the array is empty.&lt;/p&gt;&#xA;&lt;h4 id=&#34;accessinganuninitializedvariable&#34;&gt;Accessing an Uninitialized Variable&lt;/h4&gt;&#xA;&lt;p&gt;This error usually occurs in view controllers when you try to access a property in &lt;code&gt;viewDidLoad&lt;/code&gt; or similar initialization function. &lt;code&gt;viewDidLoad&lt;/code&gt; is called before the code that initializes the property, causing a crash.&lt;/p&gt;&#xA;&lt;p&gt;A common fix for accessing a property before it’s initialized is to access the property in &lt;code&gt;viewDidAppear&lt;/code&gt;, which gets called after &lt;code&gt;viewDidLoad&lt;/code&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>UndoManager Introduction Swift</title>
      <link>https://swiftdevjournal.com/undomanager-introduction/</link>
      <pubDate>Sat, 19 Jan 2019 19:39:59 +0000</pubDate>
      <guid>https://swiftdevjournal.com/undomanager-introduction/</guid>
      <description>&lt;p&gt;I recently needed to add undo support for a Mac app after not dealing with undo for several years. I noticed some subtle changes so I’m sharing what I learned here. I have not worked with the undo manager in an iOS app, but most of the material in this article should apply to iOS apps as well as Mac apps.&lt;/p&gt;&#xA;&lt;h3 id=&#34;accessingtheundomanager&#34;&gt;Accessing the Undo Manager&lt;/h3&gt;&#xA;&lt;p&gt;The first step to adding undo support in your app is to access the undo manager. Document-based Mac and iOS apps have an undo manager for each document. Use the &lt;code&gt;undoManager&lt;/code&gt; property to access the document’s undo manager.&lt;/p&gt;&#xA;&lt;p&gt;Core Data apps also have an undo manager. The managed object context has an undo manager, which you access with the &lt;code&gt;undoManager&lt;/code&gt; property.&lt;/p&gt;&#xA;&lt;h3 id=&#34;registeringanundooperation&#34;&gt;Registering an Undo Operation&lt;/h3&gt;&#xA;&lt;p&gt;When someone performs an action in your app that can be undone, register an undo operation for that action. Registering an undo operation adds the action to the undo stack so the action can be undone.&lt;/p&gt;&#xA;&lt;p&gt;The easiest way to register an undo operation is to call the &lt;code&gt;registerUndo&lt;/code&gt; method. There are two &lt;code&gt;registerUndo&lt;/code&gt; methods: one that takes a closure (unnamed function) as an argument and one that takes a selector as an argument. The method that takes a closure is the better option for Swift developers. Swift’s closure syntax is less painful to work with than its syntax for working with Objective-C selectors.&lt;/p&gt;&#xA;&lt;p&gt;When calling &lt;code&gt;registerUndo&lt;/code&gt;, supply a target for the undo operation and a closure handler that calls the function to perform the undo operation.&lt;/p&gt;&#xA;&lt;p&gt;Suppose you have a note taking app. In a note taking app people can remove notes. An important undo feature is to undo note removal. If someone accidentally removes a note, they would like to get it back.&lt;/p&gt;&#xA;&lt;p&gt;To support undoing note removal in the app, you would write two functions: one function to remove a note and a second function to restore a removed note.&lt;/p&gt;&#xA;&lt;p&gt;In the function to remove a note, call &lt;code&gt;registerUndo&lt;/code&gt;. Call the function that restores the note in the handler closure.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;removeNote&lt;/span&gt;(note: Note) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;undoManager.registerUndo(withTarget: &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { targetSelf &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    targetSelf.restoreNote(note)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  undoManager.setActionName(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Remove Note&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Code to remove the note goes here.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;removeNote&lt;/code&gt; function, the code calls &lt;code&gt;registerUndo&lt;/code&gt;. The closure is the block that starts with the brace before &lt;code&gt;targetSelf&lt;/code&gt;. The name &lt;code&gt;targetSelf&lt;/code&gt; is one I created. You can use whatever name you want to indicate the variable is the target. The closure calls the &lt;code&gt;restoreNote&lt;/code&gt; function to restore the removed note. When someone removes a note and undoes it, the app restores the note by calling &lt;code&gt;restoreNote&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The last line of code in the function sets an action name for the Undo menu item in the Edit menu. The code sets the menu item to &lt;code&gt;Undo Remove Note&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Now let’s look at the function to restore the removed note.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;restoreNote&lt;/span&gt;(note: Note) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  undoManager.registerUndo(withTarget: &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;) { targetSelf &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    targetSelf.removeNote(note)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  undoManager.setActionName(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Remove Note&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Code to restore the note goes here.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Like the &lt;code&gt;removeNote&lt;/code&gt; function, &lt;code&gt;restoreNote&lt;/code&gt; calls &lt;code&gt;registerUndo&lt;/code&gt;. The main difference is the handler closure. The handler calls &lt;code&gt;removeNote&lt;/code&gt; because removing the note is the undo operation in this case. If someone undoes removing a note and chooses Redo, the code calls &lt;code&gt;removeNote&lt;/code&gt; to redo removing the note.&lt;/p&gt;&#xA;&lt;p&gt;You might be wondering why the action name is &lt;code&gt;Remove Note&lt;/code&gt; instead of &lt;code&gt;Restore Note&lt;/code&gt;. When you undo an action in a Mac app, a Redo menu item appears in the Edit menu. In this note taking app example, when you redo, you are redoing removing a note. A menu title &lt;code&gt;Redo Remove Note&lt;/code&gt; makes more sense than &lt;code&gt;Redo Restore Note&lt;/code&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Finding the Slow Spots in Your Code with the Time Profiler Instrument</title>
      <link>https://swiftdevjournal.com/finding-the-slow-spots-in-your-code-with-the-time-profiler-instrument/</link>
      <pubDate>Mon, 07 Jan 2019 19:55:55 +0000</pubDate>
      <guid>https://swiftdevjournal.com/finding-the-slow-spots-in-your-code-with-the-time-profiler-instrument/</guid>
      <description>&lt;p&gt;I continue my coverage of Instruments with the Time Profiler instrument. If your app is running slowly, use the Time Profiler instrument to find the slow spots in your code so you know where to optimize.&lt;/p&gt;&#xA;&lt;p&gt;If you are new to Instruments, I recommend reading the &lt;a href=&#34;https://swiftdevjournal.com/measuring-your-apps-memory-usage-with-instruments/&#34;&gt;Measuring Your App&amp;rsquo;s Memory Usage with Instruments article&lt;/a&gt;. That article provides an introduction to Instruments and covers some aspects of using Instruments this article glosses over.&lt;/p&gt;&#xA;&lt;h3 id=&#34;howthetimeprofilerinstrumentworks&#34;&gt;How the Time Profiler Instrument Works&lt;/h3&gt;&#xA;&lt;p&gt;The Time Profiler instrument records the call stack every millisecond. The function at the top of the call stack is the function your app is currently executing. If a function appears at the top of the call stack in a lot of samples, that&amp;rsquo;s a sign your app is spending a lot of time in that function.&lt;/p&gt;&#xA;&lt;h3 id=&#34;launchandrecord&#34;&gt;Launch and Record&lt;/h3&gt;&#xA;&lt;p&gt;Choose Product &amp;gt; Profile in Xcode to launch Instruments. Select the Time Profiler template and click the Choose button.&lt;/p&gt;&#xA;&lt;p&gt;Click the Record button to launch your app and start profiling.&lt;/p&gt;&#xA;&lt;h3 id=&#34;controllingthegraph&#34;&gt;Controlling the Graph&lt;/h3&gt;&#xA;&lt;p&gt;When you pause recording you&amp;rsquo;ll notice the Time Profiler instrument shows a lot of graphs. There&amp;rsquo;s a graph for each thread, and iOS and Mac apps have a surprisingly high number of threads.&lt;/p&gt;&#xA;&lt;p&gt;Above the graph is a series of buttons to control what graphs appear in the trace document window.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/GraphFilter.png&#34; alt=&#34;graph filter&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;You can show instruments, threads, or CPU cores. You can also use the search field to filter what graphs appear. At the start you should focus on instruments, specifically CPU usage, because it helps find the slow spots in your code.&lt;/p&gt;&#xA;&lt;h3 id=&#34;cpuusagegraph&#34;&gt;CPU Usage Graph&lt;/h3&gt;&#xA;&lt;p&gt;Starting with Xcode 10 the Time Profiler instrument has two graphs: CPU usage and life cycle. If you move the mouse cursor over the CPU usage graph, tooltips appear with the percentage of CPU usage at that moment in the recording.&lt;/p&gt;&#xA;&lt;h3 id=&#34;lifecyclegraph&#34;&gt;Life Cycle Graph&lt;/h3&gt;&#xA;&lt;p&gt;The life cycle graph reports the current state of your app: initializing, launching, foreground, or background. If you move the mouse over the life cycle graph, tooltips tell you the state of the app and the amount of time the app was in that state.&lt;/p&gt;&#xA;&lt;p&gt;Older versions of Xcode do not have a life cycle graph.&lt;/p&gt;&#xA;&lt;h3 id=&#34;profiledata&#34;&gt;Profile Data&lt;/h3&gt;&#xA;&lt;p&gt;The Time Profiler instrument shows the call tree view initially. Click the Call Tree button at the bottom of the window and select the Invert Call Tree and Hide System Libraries checkboxes to make your code easier to find in the call tree view.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CallTreeTimeProfiler.png&#34; alt=&#34;call tree&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;For each function the call tree tells you its weight and it self weight. The weight is expressed as a time and a percentage. The weight measures the amount of time the function was on the call stack. The self weight measures the amount of time the function was at the top of the call stack.&lt;/p&gt;&#xA;&lt;p&gt;The Self Weight column is more important. Suppose you have a function A that calls functions B and C. The Weight column for A tells you the amount of time your app was in functions A, B, and C. The Self Weight column for A tells you the amount of time your app was in A. When you&amp;rsquo;re looking for the slow spots in your code, look at functions with a high self weight.&lt;/p&gt;&#xA;&lt;p&gt;Double-clicking a function opens the source view, where you can see the lines of code that take the most time in the function.&lt;/p&gt;&#xA;&lt;h3 id=&#34;narrative&#34;&gt;Narrative&lt;/h3&gt;&#xA;&lt;p&gt;The narrative section has a listing for each event in the Life Cycle graph. Each listing has the start time relative to the start of the recording and a description of what the app is doing.&lt;/p&gt;&#xA;&lt;p&gt;Older versions of Xcode do not have a narrative section.&lt;/p&gt;&#xA;&lt;h3 id=&#34;samples&#34;&gt;Samples&lt;/h3&gt;&#xA;&lt;p&gt;If you choose Samples from the jump bar, you can look at every sample the Time Profiler instrument took during the recording. Instruments shows the following data for each sample:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Sample time, relative to the start of recording&lt;/li&gt;&#xA;&lt;li&gt;Core, the CPU core&lt;/li&gt;&#xA;&lt;li&gt;Process, which is the name of your app&lt;/li&gt;&#xA;&lt;li&gt;Thread&lt;/li&gt;&#xA;&lt;li&gt;State, which is usually Running&lt;/li&gt;&#xA;&lt;li&gt;Backtrace, which lists the function at the top of the call stack&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The extended detail view shows a compressed backtrace. If you want to see every function in the call stack, click the button at the top right of the backtrace.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ExpandBacktraceHighlighted.png&#34; alt=&#34;expanded backtrace&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Remember that the Time Profiler instrument takes a sample every millisecond so there are a lot of samples to go through.&lt;/p&gt;&#xA;&lt;h3 id=&#34;cpucores&#34;&gt;CPU Cores&lt;/h3&gt;&#xA;&lt;p&gt;If you move the mouse cursor over a CPU core in the graph, a tooltip appears showing you the percentage of CPU usage for that core at that moment in the recording.&lt;/p&gt;&#xA;&lt;p&gt;Selecting a CPU core from the instrument list fills the detail view with call tree statistics for that core. Choosing Samples from the jump bar shows all the samples Instruments recorded for that CPU core.&lt;/p&gt;&#xA;&lt;h3 id=&#34;threads&#34;&gt;Threads&lt;/h3&gt;&#xA;&lt;p&gt;If you move the mouse cursor over a thread in the graph, a tooltip appears showing the percentage of CPU usage for that thread at that moment in the recording. The graph can tell you if the main thread is doing too much work.&lt;/p&gt;&#xA;&lt;p&gt;Selecting a thread from the instrument list fills the detail view with call tree statistics for that thread. Choosing Samples from the jump bar shows all the samples Instruments recorded for that thread.&lt;/p&gt;&#xA;&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;&#xA;&lt;p&gt;The main point of using the Time Profiler instrument is to find the slow spots in your code. Look for functions in the call tree with a high self weight. If you need to make your app run faster, start by optimizing those functions with a high self weight.&lt;/p&gt;&#xA;&lt;h2 id=&#34;do-you-want-to-learn-more-about-instruments&#34;&gt;Do you want to learn more about Instruments?&lt;/h2&gt;&#xA;&lt;p&gt;I wrote a book, &lt;em&gt;Profiling Swift Apps&lt;/em&gt;, that shows you how to use Instruments to find and fix problems in your code. The book will help you make apps that run faster and use less memory. You can learn more about the book and download a sample at the following link:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/instruments-book/&#34;&gt;Profiling Swift Apps page&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Creating a Draggable iOS View</title>
      <link>https://swiftdevjournal.com/creating-a-draggable-ios-view/</link>
      <pubDate>Thu, 27 Dec 2018 23:29:19 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-a-draggable-ios-view/</guid>
      <description>&lt;p&gt;Some iOS apps have items like cards or sticky notes that you can drag. Making an iOS view draggable is less difficult than you think. Use a pan gesture recognizer, and you can drag a view around with your finger.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thesteps&#34;&gt;The Steps&lt;/h3&gt;&#xA;&lt;p&gt;Take the following steps to create a draggable view in iOS:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Add a view to the view controller scene in your storyboard.&lt;/li&gt;&#xA;&lt;li&gt;Drag a pan gesture recognizer to the view so the view becomes draggable.&lt;/li&gt;&#xA;&lt;li&gt;Create an action (IBAction) for the pan gesture recognizer by making a connection from the storyboard to the view controller’s source code file. Set the type for the sender to &lt;code&gt;UIPanGestureRecognizer&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I have a &lt;a href=&#34;https://github.com/SwiftDevJournal/DraggableView&#34;&gt;demo project for draggable views on GitHub&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thecode&#34;&gt;The Code&lt;/h3&gt;&#xA;&lt;p&gt;To make the view move around when you drag it, you must implement the action for the pan gesture recognizer. The following code shows an example of panning a view:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@IBAction func panView(_ sender: UIPanGestureRecognizer) {&#xA;  let translation = sender.translation(in: self.view)&#xA;    &#xA;  if let viewToDrag = sender.view {&#xA;    viewToDrag.center = CGPoint(x: viewToDrag.center.x + translation.x, &#xA;      y: viewToDrag.center.y + translation.y)&#xA;    sender.setTranslation(CGPoint(x: 0, y: 0), in: viewToDrag)&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By setting the type of the IBAction to &lt;code&gt;UIPanGestureRecognizer&lt;/code&gt;, you can access the view being dragged through the pan gesture recognizer’s &lt;code&gt;view&lt;/code&gt; property.&lt;/p&gt;&#xA;&lt;p&gt;The first line of code determines how far the view dragged. Using an &lt;code&gt;if-let&lt;/code&gt; statement avoids force unwrapping optionals when accessing the dragged view.&lt;/p&gt;&#xA;&lt;p&gt;The first line of code inside the &lt;code&gt;if-let&lt;/code&gt; block moves the center of the view by the amount of the drag. The second line of code clears the translation for future drags.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Measuring Your App’s Memory Usage with Instruments</title>
      <link>https://swiftdevjournal.com/measuring-your-apps-memory-usage-with-instruments/</link>
      <pubDate>Fri, 14 Dec 2018 05:11:05 +0000</pubDate>
      <guid>https://swiftdevjournal.com/measuring-your-apps-memory-usage-with-instruments/</guid>
      <description>&lt;p&gt;On Stack Overflow I see many questions from people who have trouble interpreting the data Instruments generates. After reading this article you&amp;rsquo;ll know how to interpret the data Instruments generates for the Allocations and Leaks instruments and learn tips you can use with other instruments.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatisinstruments&#34;&gt;What is Instruments?&lt;/h3&gt;&#xA;&lt;p&gt;Instruments is an app that is bundled with Xcode to record and display statistics about your app as it runs. Instruments comes with a collection of instruments, each of which records a specific set of statistics. Some popular instruments include the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The Leaks instrument checks your app for memory leaks.&lt;/li&gt;&#xA;&lt;li&gt;The Allocations instrument records statistics about memory allocations.&lt;/li&gt;&#xA;&lt;li&gt;The Time Profiler instrument measures CPU usage and helps you find the slow spots in your code.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you&amp;rsquo;re learning iOS or Mac development, you&amp;rsquo;re not going to use Instruments at first. You normally use Instruments when you get closer to shipping an app. But if your iOS app is generating memory warnings when you run it or your app runs really slow, you&amp;rsquo;ll want to profile the app with Instruments.&lt;/p&gt;&#xA;&lt;h3 id=&#34;launchinginstruments&#34;&gt;Launching Instruments&lt;/h3&gt;&#xA;&lt;p&gt;Because Instruments is located inside Xcode&amp;rsquo;s app bundle, you won&amp;rsquo;t be able to find it in the Finder. The easiest way to launch Instruments is to profile your project by choosing Product &amp;gt; Profile in Xcode. When Instruments launches, you will be asked to choose a template.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ChooseTemplateHighlighted.png&#34; alt=&#34;choose Instruments template&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the Leaks template and click the Choose button. The Leaks template include both the Leaks and Allocations instruments.&lt;/p&gt;&#xA;&lt;h3 id=&#34;thetracedocumentwindow&#34;&gt;The Trace Document Window&lt;/h3&gt;&#xA;&lt;p&gt;When you click the Choose button, an empty trace document window opens in Instruments.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/TraceDocumentWindowHighlighted.png&#34; alt=&#34;trace document window&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Running from top to bottom, the main areas of the trace document window are the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Toolbar&lt;/li&gt;&#xA;&lt;li&gt;Instrument list&lt;/li&gt;&#xA;&lt;li&gt;Jump bar&lt;/li&gt;&#xA;&lt;li&gt;Detail view&lt;/li&gt;&#xA;&lt;li&gt;Extended detail view&lt;/li&gt;&#xA;&lt;li&gt;Bottom bar&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;For this article the only toolbar items you need to worry about are the buttons to start/stop recording and pause recording on the left side of the toolbar. The toolbar also has controls to choose an app to profile, add an instrument to the trace, and show/hide different parts of the trace document window.&lt;/p&gt;&#xA;&lt;p&gt;The instrument list shows the instruments being used in the trace along with a graph for each instrument. The graph is going to be empty until you start recording.&lt;/p&gt;&#xA;&lt;p&gt;The jump bar allows you to choose what to show in the detail view. The detail view shows the profiling statistics. The extended detail view shows additional statistics. For most instruments the extended detail view shows the call stack.&lt;/p&gt;&#xA;&lt;p&gt;The bottom bar contains controls to filter the information that appears in the detail view.&lt;/p&gt;&#xA;&lt;h3 id=&#34;configuringaninstrumentoptional&#34;&gt;Configuring an Instrument (Optional)&lt;/h3&gt;&#xA;&lt;p&gt;You won&amp;rsquo;t need to configure any instruments to follow along with this tutorial. But when you use Instruments, you may need to configure an instrument, and it helps to configure the instrument before you start recording.&lt;/p&gt;&#xA;&lt;p&gt;Choose File &amp;gt; Recording Options to configure an instrument. The following screenshot shows the configuration options for the Allocations instrument:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/RecordingOptionsHighlighted.png&#34; alt=&#34;trace recording options&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;profilingyourapp&#34;&gt;Profiling Your App&lt;/h3&gt;&#xA;&lt;p&gt;At this point you can start profiling your app. Click the Record button on the left side of the toolbar. Your app will launch. Use your app. When you are finished, you can either click the Pause button or the Stop button. The Leaks instrument is set to check for leaks every 10 seconds so you should run your app for at least 10 seconds.&lt;/p&gt;&#xA;&lt;p&gt;If you want to save your trace so you can look at the results later, choose File &amp;gt; Save.&lt;/p&gt;&#xA;&lt;h3 id=&#34;readingtheprofilingdata&#34;&gt;Reading the Profiling Data&lt;/h3&gt;&#xA;&lt;p&gt;Now comes the hard part: making sense of all the data that Instruments generates. Let&amp;rsquo;s start with the graph. If you move the mouse cursor inside the graph, Instruments shows a tooltip with a piece of data about the graph. The following image shows the memory usage for the Allocations instrument:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/MemoryToolTip.png&#34; alt=&#34;memory tool tip&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;You can focus on a specific time interval in the graph by setting an inspection range. Click inside an instrument&amp;rsquo;s graph and drag to create the inspection range. The inspection range is shaded blue, which you can see in the following screenshot:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/PartialGraphTimePeriod.png&#34; alt=&#34;partial graph time period&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;When you set an inspection range, the statistics in the detail view change to reflect the time interval in the inspection range. Clicking in the graph outside of the inspection range you set clears the inspection range.&lt;/p&gt;&#xA;&lt;h3 id=&#34;allocationsinstrumentresults&#34;&gt;Allocations Instrument Results&lt;/h3&gt;&#xA;&lt;p&gt;Now it&amp;rsquo;s time to look at data for specific instruments. Let&amp;rsquo;s start with the Allocations instrument. If you select the Allocations instrument from the instrument list, the detail view shows a summary of the memory allocation data. The most important data is at the top.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/MemoryUsage.png&#34; alt=&#34;memory usage stats&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;To determine how much memory your app is currently using, look at the Persistent Bytes column for the category All Heap Allocations. The text is a little small in the screenshot, but it says the app is using 9.64 MB of memory, which is good for an iOS or Mac app. The Allocations instrument does not record OpenGL/ES or Metal texture memory. If your app allocates texture memory, your actual memory use will be higher than what Instruments reports. You may also want to click the checkbox in the Graph column to show the heap allocation totals in the graph.&lt;/p&gt;&#xA;&lt;p&gt;The Allocations instrument has the following columns of data for each memory category:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Persistent Bytes, which is the amount of allocated memory that hasn&amp;rsquo;t been freed yet.&lt;/li&gt;&#xA;&lt;li&gt;# Persistent, which is the number of memory allocations that haven&amp;rsquo;t been freed yet.&lt;/li&gt;&#xA;&lt;li&gt;# Transient, which is the total number of memory allocations that have been freed.&lt;/li&gt;&#xA;&lt;li&gt;Total Bytes, which is the total amount of allocated memory, including freed memory.&lt;/li&gt;&#xA;&lt;li&gt;# Total, which is the total number of memory allocations, including freed memory. The # Total column should equal the sum of the # Persistent and # Transient columns.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Suppose your app makes 20 memory allocations of 1,000 bytes and frees the memory for 15 of the allocations. The Allocations instrument would report the following information:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Persistent Bytes: 5,000&#xA;# Persistent: 5&#xA;# Transient: 15&#xA;Total Bytes: 20,000&#xA;# Total: 20&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;allocationsinstrumentcalltree&#34;&gt;Allocations Instrument Call Tree&lt;/h3&gt;&#xA;&lt;p&gt;If your app allocates a high amount of memory, the first thing you&amp;rsquo;ll want to know is where your code is making the big memory allocations. To find where you&amp;rsquo;re allocating memory, switch to the call tree view. In the jump bar, click on Statistics and choose Call Trees to switch to the call tree view.&lt;/p&gt;&#xA;&lt;p&gt;When you switch to the call tree view, you should configure Instruments to make finding your code easier in the call tree view. Click the Call Tree button in the bottom bar to open a popover with a series of checkboxes.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/InvertCallTree.png&#34; alt=&#34;invert call tree&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the Invert Call Tree and Hide System Libraries checkboxes. Inverting the call tree brings the memory allocating functions to the top. Hiding the system libraries hides Apple&amp;rsquo;s code, leaving your code in the call tree view.&lt;/p&gt;&#xA;&lt;p&gt;After selecting the checkboxes, the call tree view should show your code.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CallTree.png&#34; alt=&#34;call tree&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Option-clicking a disclosure triangle next to a function in the call tree view expands its subtree so you don&amp;rsquo;t have to be constantly clicking disclosure triangles. Option-clicking again on the expanded disclosure triangle contracts the subtree.&lt;/p&gt;&#xA;&lt;p&gt;For each function in the call tree, the Allocations instrument shows the bytes used and the allocation count. The bytes used is represented both as an amount and a percentage of the total memory allocated. Here&amp;rsquo;s the listing from the &lt;code&gt;Framesetter.init&lt;/code&gt; listing:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;308.86 KB   1.2%    42&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The line says the &lt;code&gt;Framesetter.init&lt;/code&gt; function and any functions in its subtree allocated 308.86 KB of memory, which is 1.2% percent of the total allocated memory. This function and any functions in its subtree made 42 allocations.&lt;/p&gt;&#xA;&lt;p&gt;The subtrees keep Instruments from telling you the exact amount of memory each function allocates. Inverting the call tree reduces the subtree, which makes the listing for a function in an inverted call tree the closest approximation to the amount of memory that function is allocating. If you set an inspection range in the graph, the listing reflects the amount of memory allocated in the inspection range&amp;rsquo;s time interval.&lt;/p&gt;&#xA;&lt;h4 id=&#34;mainlisting&#34;&gt;main Listing&lt;/h4&gt;&#xA;&lt;p&gt;For most Mac and iOS apps, the first listing in the call tree view is the &lt;code&gt;main&lt;/code&gt; function. This function is going to have a high amount of bytes used and allocations. If you don&amp;rsquo;t invert the call tree, the &lt;code&gt;main&lt;/code&gt; function will show 100% bytes used. That&amp;rsquo;s because &lt;code&gt;main&lt;/code&gt; is the starting point of your app. Every function in your app will have &lt;code&gt;main&lt;/code&gt; in its call stack so every memory allocation your app makes will have &lt;code&gt;main&lt;/code&gt; in its call stack.&lt;/p&gt;&#xA;&lt;p&gt;When trying to figure out where your app allocates memory, don&amp;rsquo;t worry about the &lt;code&gt;main&lt;/code&gt; listing. The &lt;code&gt;main&lt;/code&gt; function doesn&amp;rsquo;t do much in most Mac and iOS apps. There isn&amp;rsquo;t much you can do in the &lt;code&gt;main&lt;/code&gt; function to reduce your app&amp;rsquo;s memory usage.&lt;/p&gt;&#xA;&lt;h4 id=&#34;sourceview&#34;&gt;Source View&lt;/h4&gt;&#xA;&lt;p&gt;Double-clicking a function in the call tree view shows the source view. For the Allocations instrument, the source view shows you the lines of code that allocated the memory along with the percentage of memory allocated. The percentage is relative to the function. If a line of code says 80%, it means that line of code allocated 80% of the memory the function allocated.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SourceCodeView.png&#34; alt=&#34;source view&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Notice how each listing in the source view has an icon with an exclamation point. Clicking that icon shows the heaviest call stack for that line of code.&lt;/p&gt;&#xA;&lt;h3 id=&#34;leaksinstrumentresults&#34;&gt;Leaks Instrument Results&lt;/h3&gt;&#xA;&lt;p&gt;Now it&amp;rsquo;s time to look at the Leaks instrument. The graph will tell you if you have any memory leaks in your app. A memory leak occurs when your app allocates memory and never frees the memory. The following screenshot shows an example of the graph for the Leaks instrument:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/LeaksGraph.png&#34; alt=&#34;leaks graph&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The screenshot shows six memory leak checks. For the first four checks, Leaks found no memory leaks so it leaves a green icon with a checkmark on the graph. On the fifth check, Leaks found some leaks so it leaves a red icon with an X on the graph. On the last check Leaks found no new leaks so it leaves a gray icon with a dash on the graph.&lt;/p&gt;&#xA;&lt;h3 id=&#34;leaksinstrumentcalltree&#34;&gt;Leaks Instrument Call Tree&lt;/h3&gt;&#xA;&lt;p&gt;If Instruments finds memory leaks in your app, the next step is to find where the leaks are occurring in your code. The steps to do this are the same as for the Allocations instrument: switch to the call tree view by using the jump bar and select the Invert Call Tree and Hide System Libraries checkboxes from the Call Tree popover in the bottom bar. Selecting the checkboxes will limit the call tree listing to functions you wrote.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/LeaksCallTree.png&#34; alt=&#34;leaks call tree&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;For each function in the call tree listing, Instruments shows the bytes used and the number of leaks. Like the Allocations instrument, the bytes used is represented both as an amount and a percentage, but in the Leaks instrument the percentage represents the percentage of total leaked memory. Here&amp;rsquo;s the listing for the &lt;code&gt;malloc&lt;/code&gt; function in the screenshot.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;19.12 KB    98.0%   92&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The listing says the &lt;code&gt;malloc&lt;/code&gt; function has 92 memory leaks totaling 19.12 KB. The leaks totaled 98% of the leaked memory in the app.&lt;/p&gt;&#xA;&lt;p&gt;Double-click any functions in your call tree view to see where the leaked memory is allocated.&lt;/p&gt;&#xA;&lt;p&gt;The fact that a function allocates leaked memory doesn&amp;rsquo;t necessarily mean the function is responsible for leaking the memory. But it&amp;rsquo;s a good place to start looking for the source of the leak.&lt;/p&gt;&#xA;&lt;h3 id=&#34;troubleshooting&#34;&gt;Troubleshooting&lt;/h3&gt;&#xA;&lt;p&gt;This section contains fixes for common issues people run into with Instruments.&lt;/p&gt;&#xA;&lt;h4 id=&#34;thecalltreeviewshowsmemoryaddresses&#34;&gt;The Call Tree View Shows Memory Addresses&lt;/h4&gt;&#xA;&lt;p&gt;A problem many people run into when using Instruments is the call tree view shows memory addresses instead of the names of functions. The usual cause of this problem is Instruments being unable to locate the dSYM file that contains the project&amp;rsquo;s debugging symbols. The function names are in the debugging symbols.&lt;/p&gt;&#xA;&lt;p&gt;To locate the dSYM file, choose File &amp;gt; Symbols in Instruments. A sheet like the following will open:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/LocatedSYMHighlighted.png&#34; alt=&#34;locate dSYM file&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select your app from the left side of the sheet. Click the Locate button to find the dSYM file.&lt;/p&gt;&#xA;&lt;p&gt;The dSYM file is usually located in the same directory as the app bundle of the release version of your project. The app bundle is in the Derived Data folder. You can check the location of your Derived Data folder in Xcode by choosing File &amp;gt; Project Settings, but the Derived Data folder is usually in the following folder:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/Users/YourUsername/Library/Developer/Xcode/DerivedData&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There will be a folder for your project in the Derived Data folder with a long string of random characters after the project name. The release version of the project is in the following folder:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;.../DerivedData/ProjectName/Build/Products/Release&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An iOS project will have the name &lt;code&gt;Release-iphoneos&lt;/code&gt; instead of &lt;code&gt;Release&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h4 id=&#34;thesourceviewdoesntshowsourcecode&#34;&gt;The Source View Doesn&amp;rsquo;t Show Source Code&lt;/h4&gt;&#xA;&lt;p&gt;You double-click a function in the call tree view, expecting to see that function&amp;rsquo;s code in the source view. But instead you see either assembly language code or a blank view that says Unavailable.&lt;/p&gt;&#xA;&lt;p&gt;The usual cause of this issue is double-clicking a function you didn&amp;rsquo;t write. Examples of functions you didn&amp;rsquo;t write include functions from Apple&amp;rsquo;s frameworks and default initializers in your structs and classes. Make sure you double-click a function you wrote.&lt;/p&gt;&#xA;&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;&#xA;&lt;p&gt;I want to summarize the most important points to take away from this article. These points apply to most instruments, not just the Leaks and Allocations instruments.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Choose Product &amp;gt; Profile in Xcode to profile your app.&lt;/li&gt;&#xA;&lt;li&gt;Use the call tree view to find problem areas in your code.&lt;/li&gt;&#xA;&lt;li&gt;Select the Invert Call Tree and Hide System Libraries checkboxes to find your code in the call tree view.&lt;/li&gt;&#xA;&lt;li&gt;Option-click the disclosure triangles in the call tree view to minimize the amount of clicking you have to do.&lt;/li&gt;&#xA;&lt;li&gt;Double-click a function in the call tree view to see statistics on specific lines of code.&lt;/li&gt;&#xA;&lt;li&gt;Don&amp;rsquo;t worry about the listing for the &lt;code&gt;main&lt;/code&gt; function in the call tree view. You have no control over &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;do-you-want-to-learn-more-about-instruments&#34;&gt;Do you want to learn more about Instruments?&lt;/h2&gt;&#xA;&lt;p&gt;I wrote a book, &lt;em&gt;Profiling Swift Apps&lt;/em&gt;, that shows you how to use Instruments to find and fix problems in your code. The book will help you make apps that run faster and use less memory. You can learn more about the book and download a sample at the following link:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/instruments-book/&#34;&gt;Profiling Swift Apps page&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Learning iOS Development</title>
      <link>https://swiftdevjournal.com/learning-ios-development/</link>
      <pubDate>Wed, 05 Dec 2018 20:01:09 +0000</pubDate>
      <guid>https://swiftdevjournal.com/learning-ios-development/</guid>
      <description>&lt;p&gt;Last update: December 2025&lt;/p&gt;&#xA;&lt;p&gt;A lot of people are interested in developing iOS apps but don’t know where to get started. Getting started questions come up frequently on Reddit’s iOS programming forum and the same answers pop up over and over again so I’m compiling them here.&lt;/p&gt;&#xA;&lt;h3 id=&#34;hackingwithswift&#34;&gt;Hacking with Swift&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.hackingwithswift.com&#34;&gt;Hacking with Swift&lt;/a&gt; is a website that teaches Swift and iOS development. They have a &lt;a href=&#34;https://www.hackingwithswift.com/read&#34;&gt;free book&lt;/a&gt; that teaches the Swift language by building 39 projects. The site also has free 100 day iOS development courses, one that uses UIKit and one that uses SwiftUI.&lt;/p&gt;&#xA;&lt;p&gt;When you finish the free book, Hacking with Swift has books you can buy to delve deeper into Swift and iOS development.&lt;/p&gt;&#xA;&lt;h3 id=&#34;stanfordscs193pcourse&#34;&gt;Stanford’s CS193P Course&lt;/h3&gt;&#xA;&lt;p&gt;If you have experience developing software on other platforms and want to quickly get up to speed developing iOS apps, Stanford has their &lt;a href=&#34;https://cs193p.stanford.edu&#34;&gt;CS193P course on iOS development&lt;/a&gt; available for free.&lt;/p&gt;&#xA;&lt;p&gt;Keep in mind that this is a college course at Stanford that students take in one quarter. This course moves at a much faster pace than Hacking with Swift.&lt;/p&gt;&#xA;&lt;h3 id=&#34;angelayusudemycourse&#34;&gt;Angela Yu’s Udemy Course&lt;/h3&gt;&#xA;&lt;p&gt;If you prefer video learning and want something that moves at a slower pace than the Stanford course, check out Angela Yu’s &lt;a href=&#34;https://www.udemy.com/ios-13-app-development-bootcamp/&#34;&gt;iOS App Development Bootcamp&lt;/a&gt;. This course is not free, but it gets recommended a lot when people ask how to get started with iOS development.&lt;/p&gt;&#xA;&lt;h3 id=&#34;kodeco&#34;&gt;Kodeco&lt;/h3&gt;&#xA;&lt;p&gt;When you go through one or more of the resources I mentioned earlier in this article, you’ll be ready for &lt;a href=&#34;https://kodeco.com&#34;&gt;Kodeco&lt;/a&gt;. Kodeco has a vast collection of text and video tutorials on iOS development as well as books to buy. They are moving towards more video tutorials. The tutorials tend to focus on one specific topic, such as table views. After you learn the basics of iOS development and want to go deeper on a specific topic, check out Kodeco&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Checking API Availability in Swift</title>
      <link>https://swiftdevjournal.com/checking-api-availability-in-swift/</link>
      <pubDate>Tue, 27 Nov 2018 20:51:49 +0000</pubDate>
      <guid>https://swiftdevjournal.com/checking-api-availability-in-swift/</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://swiftdevjournal.com/supporting-older-versions-of-ios-and-macos/&#34;&gt;a previous article&lt;/a&gt; I explained how to set up your Xcode projects to support older versions of iOS and macOS. But I didn’t explain how to use new functions on new iOS and macOS versions and older functions on older systems.&lt;/p&gt;&#xA;&lt;p&gt;Swift provides two statements to help support older OS versions: &lt;code&gt;#available&lt;/code&gt; and &lt;code&gt;@available&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;available&#34;&gt;#available&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;code&gt;#available&lt;/code&gt; keyword works with &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;guard&lt;/code&gt; statements. Supply an operating system version version, and the code inside the &lt;code&gt;if&lt;/code&gt; block runs only on suitable systems.&lt;/p&gt;&#xA;&lt;p&gt;Let’s work through an example. Apple added the &lt;code&gt;NSPersistentContainer&lt;/code&gt; class in iOS 10 and macOS 10.12 to simplify setting up the Core Data stack. You would like to use &lt;code&gt;NSPersistentContainer&lt;/code&gt; on systems that have the class and not use it on older versions of iOS and macOS. The following example shows how to use &lt;code&gt;NSPersistentContainer&lt;/code&gt; on systems running iOS 10 and later:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#available&lt;/span&gt; (&lt;span style=&#34;color:#75715e&#34;&gt;iOS&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// Use NSPersistentContainer to set up Core Data stack&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Set up the Core Data stack the old way&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The asterisk as the second argument to &lt;code&gt;#available&lt;/code&gt; tells the compiler to require the minimum deployment target for other platforms. The minimum deployment target is the earliest version of iOS or macOS that can run your app.&lt;/p&gt;&#xA;&lt;p&gt;The following code shows how to use &lt;code&gt;NSPersistentContainer&lt;/code&gt; on systems running macOS 10.12 and later:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#available&lt;/span&gt; (&lt;span style=&#34;color:#75715e&#34;&gt;OSX&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10.12&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// Use NSPersistentContainer to set up Core Data stack&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Set up the Core Data stack the old way&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Apple added the &lt;code&gt;#available&lt;/code&gt; statement before changing the name of the Mac operating system from OS X to macOS.&lt;/p&gt;&#xA;&lt;p&gt;If you have some code that should run only on later versions of iOS or macOS, use &lt;code&gt;#available&lt;/code&gt; with a &lt;code&gt;guard&lt;/code&gt; statement. By using &lt;code&gt;#available&lt;/code&gt; with &lt;code&gt;guard&lt;/code&gt;, your code can exit if it’s running on an older version of iOS or macOS.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#available&lt;/span&gt;(&lt;span style=&#34;color:#75715e&#34;&gt;iOS&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Exit on iOS 10 and earlier&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Call the functions added in iOS 11.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;available&#34;&gt;@available&lt;/h3&gt;&#xA;&lt;p&gt;Place &lt;code&gt;@available&lt;/code&gt; in front of a function or class to make that function or class available only on supported iOS and Mac versions. Like &lt;code&gt;#available&lt;/code&gt;, supply an operating system version. The following code shows how to use &lt;code&gt;@available&lt;/code&gt; with a function:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@available(iOS &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;myFunctionThatRequiresIOS12&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following code uses &lt;code&gt;@available&lt;/code&gt; with a class:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@available(OSX &lt;span style=&#34;color:#ae81ff&#34;&gt;10.13&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyHighSierraClass&lt;/span&gt;: NSObject {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Supporting Older Versions of iOS and macOS</title>
      <link>https://swiftdevjournal.com/supporting-older-versions-of-ios-and-macos/</link>
      <pubDate>Mon, 19 Nov 2018 19:53:05 +0000</pubDate>
      <guid>https://swiftdevjournal.com/supporting-older-versions-of-ios-and-macos/</guid>
      <description>&lt;p&gt;I recently answered a question from someone who wanted to know what version of Xcode and Swift to use to develop an app for iOS 9 and another question from someone who wanted to know what version of Xcode to use to develop an app to run on macOS 10.7. Answering what is basically the same question twice in one week is a sign that people are not sure how to make their apps run on older versions of iOS and macOS. This article should clarify things.&lt;/p&gt;&#xA;&lt;p&gt;Short version: use the latest version of Xcode and set the deployment target for the project to the earliest version of iOS or macOS you want to support.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatversionofxcodeshouldyouuse&#34;&gt;What Version of Xcode Should You Use?&lt;/h3&gt;&#xA;&lt;p&gt;You should use the most recent version of Xcode that will run on your Mac. Currently the most recent version of Xcode is version 10.1, which runs on macOS 10.13 and 10.14. The site &lt;a href=&#34;https://xcodereleases.com&#34;&gt;Xcode Releases&lt;/a&gt; has a list of every Xcode release and the operating system requirements.&lt;/p&gt;&#xA;&lt;p&gt;Why should you use the most recent Xcode version? Each version of Xcode ships with a SDK (Software Development Kit) for iOS and macOS. Xcode 10 ships with the iOS 12 and macOS 10.14 SDKs. The SDK contains the features your app can use. By using the latest SDK, your app can take advantage of the features Apple added in the latest version of iOS and macOS. The macOS 10.14 SDK includes support for dark mode. If you want your Mac app to look good in dark mode, you have to build it with the 10.14 SDK.&lt;/p&gt;&#xA;&lt;p&gt;Some of you are asking the following question: if I use the iOS 12 SDK, will my app run only on devices running iOS 12? No. The SDK determines the latest features your app can take advantage of. The deployment target determines the operating systems that can run your app. If you use the iOS 12 SDK and set the deployment target to iOS 10, your app can run on devices running iOS 10, 11, and 12 (and future versions of iOS too).&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatversionofswiftshouldyouuse&#34;&gt;What Version of Swift Should You Use?&lt;/h3&gt;&#xA;&lt;p&gt;All versions of Swift support the same operating systems: iOS 7 and later and macOS 10.9 and later. You can use the latest version of Swift and support older versions of iOS and macOS.&lt;/p&gt;&#xA;&lt;p&gt;The main reason to use an older version of Swift is if you are using any non-Apple libraries or frameworks that were built with an older version of Swift. In that situation you should use the same version of Swift that was used to build the library or framework.&lt;/p&gt;&#xA;&lt;h3 id=&#34;settingthedeploymenttargetforyourproject&#34;&gt;Setting the Deployment Target for Your Project&lt;/h3&gt;&#xA;&lt;p&gt;To make your app run on older versions of iOS and macOS, change the deployment target for your project by selecting the project file from the left side of the project window.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SetiOSDeploymentTarget.png&#34; alt=&#34;set iOS deployment target&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The deployment target is the earliest version of iOS or macOS that can run your app. Set the deployment target to the earliest version of iOS or macOS that you want to support. Keep in mind that Apple makes supporting earlier versions of iOS and macOS difficult. Most app developers support the most recent operating system version and the previous version, such as supporting iOS 11 and 12.&lt;/p&gt;&#xA;&lt;p&gt;Setting the deployment target is mandatory for your app to run on older versions of iOS and macOS, but it’s not the only thing you have to do. You have to make sure your app isn’t using any technologies or calling any code that Apple introduced in a later iOS or macOS version. As an example Apple added a document browser class, &lt;code&gt;UIDocumentBrowserViewController&lt;/code&gt;, in iOS 11 to simplify creating and opening documents. If your app uses the new document browser, it will run only on iOS 11 and later. Setting the deployment target to iOS 9 isn’t going to make your document-based app run on iOS 9 or 10.&lt;/p&gt;&#xA;&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;&#xA;&lt;p&gt;Use the latest version of Xcode so your app can take advantage of the latest features in iOS and macOS. Change the deployment target for your project to support earlier versions of iOS and macOS, making sure not to use any new technologies or functions.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Swift Optionals</title>
      <link>https://swiftdevjournal.com/swift-optionals/</link>
      <pubDate>Thu, 15 Nov 2018 05:04:41 +0000</pubDate>
      <guid>https://swiftdevjournal.com/swift-optionals/</guid>
      <description>&lt;p&gt;I saw in &lt;a href=&#34;https://vimeo.com/291590798&#34;&gt;a talk by Paul Hudson at NSSpain 2018&lt;/a&gt; that optionals are what people learning Swift struggle with the most. That makes optionals a good topic to cover on a site called Swift Dev Journal.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatisanoptional&#34;&gt;What Is an Optional?&lt;/h3&gt;&#xA;&lt;p&gt;An optional is a data type for a variable where the variable either exists or doesn’t exist, in which case it’s &lt;code&gt;nil&lt;/code&gt;. Pretty much anything in Swift can be an optional, including integers, strings, views, structs, and classes. Add &lt;code&gt;?&lt;/code&gt; to a variable’s type to make that variable an optional.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; description: String?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example if there’s a description, the &lt;code&gt;description&lt;/code&gt; variable contains a string with the description. If there’s no description, &lt;code&gt;description&lt;/code&gt; is nil.&lt;/p&gt;&#xA;&lt;h3 id=&#34;implicitlyunwrappedoptionals&#34;&gt;Implicitly Unwrapped Optionals&lt;/h3&gt;&#xA;&lt;p&gt;A special kind of optional is an implicitly unwrapped optional. An implicitly unwrapped optional assumes the value of the optional is not nil. If the value is nil and you access that value in your app, the app crashes. Add &lt;code&gt;!&lt;/code&gt; to a variable’s type to make that variable an implicitly unwrapped optional.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@IBOutlet&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; textView: UITextView!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Outlets are the most common use of implicitly unwrapped optionals. You can assume your outlets are not nil after loading a storyboard or xib file. If you forget to connect the outlets, your app will crash, but in that case, you want the app to crash so you can connect the outlets.&lt;/p&gt;&#xA;&lt;p&gt;Outside of outlets you should avoid using implicitly unwrapped optionals because they’re not safe. Every implicitly unwrapped optional in your code is a potential crash.&lt;/p&gt;&#xA;&lt;h3 id=&#34;forceunwrapping&#34;&gt;Force Unwrapping&lt;/h3&gt;&#xA;&lt;p&gt;Force unwrapping an optional uses the value without checking if it’s nil. Add &lt;code&gt;!&lt;/code&gt; to an optional variable to force unwrap it.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(description!)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Don’t force unwrap implicitly unwrapped optionals. They’re already unwrapped. If you add &lt;code&gt;!&lt;/code&gt; to an implicitly unwrapped optional, you’ll get a compiler error.&lt;/p&gt;&#xA;&lt;p&gt;Force unwrapping is dangerous. In this example if &lt;code&gt;description&lt;/code&gt; is nil, the app will crash.&lt;/p&gt;&#xA;&lt;p&gt;You should avoid force unwrapping optionals because force unwrapping isn’t safe. Every optional you force unwrap is a potential crash.&lt;/p&gt;&#xA;&lt;h3 id=&#34;safelyunwrappingwithif-letandguard&#34;&gt;Safely Unwrapping with if-let and guard&lt;/h3&gt;&#xA;&lt;p&gt;When writing Swift code, you often end up checking if an optional value is not nil, then assigning a constant with something from the optional value. Suppose you wanted to get a view controller’s parent (which is an optional because a view controller may not have a parent) and do something with it, you could write code like the following:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; parent &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; parentViewController = parent&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Do something with parentViewController&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But this code is a bit tedious to write. Swift provides the &lt;code&gt;if-let&lt;/code&gt; statement to combine the nil check and the assignment into one statement.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; parentViewController = parent {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Do something with parentViewController&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;parent&lt;/code&gt; is nil, the code inside the &lt;code&gt;if&lt;/code&gt; block won’t execute.&lt;/p&gt;&#xA;&lt;p&gt;Another way to safely unwrap an optional is to use a &lt;code&gt;guard&lt;/code&gt; statement. The &lt;code&gt;guard&lt;/code&gt; statement lets you exit quickly if the optional value is nil.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; parentViewController = parent &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; { &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Do something with parentViewController&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Make a Simple Mac App in Swift</title>
      <link>https://swiftdevjournal.com/make-a-simple-mac-app-in-swift/</link>
      <pubDate>Mon, 12 Nov 2018 05:03:05 +0000</pubDate>
      <guid>https://swiftdevjournal.com/make-a-simple-mac-app-in-swift/</guid>
      <description>&lt;p&gt;I have seen some questions from people looking for information on developing Mac apps in Swift. To help people who want to write Mac apps in Swift, I’ve written this tutorial that walks you through creating a simple Mac app in Swift. The app generates and displays a random number when you click a button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createtheproject&#34;&gt;Create the Project&lt;/h3&gt;&#xA;&lt;p&gt;The first step is to open Xcode and create a project. Choose File &amp;gt; New &amp;gt; Project to create a new Xcode project. The New Project Assistant opens.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/NewProjectStep1.png&#34; alt=&#34;new project step 1&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The project is a Mac app so click the macOS button at the top of the window. Select Cocoa App. Click the Next button to move on to the next step.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/NewProjectStep2.png&#34; alt=&#34;new project step 2&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter the name of the project in the Product Name text field.&lt;/p&gt;&#xA;&lt;p&gt;Select None from the Team menu. You need a team only if you’re going to submit an app to the Mac App Store. This project is not going on the Mac App Store.&lt;/p&gt;&#xA;&lt;p&gt;Enter either your name or a company name in the Organization Name text field. Use the organization name to fill out the organization identifier, which takes the form &lt;code&gt;com.OrganizationName&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Choose Swift from the Language menu.&lt;/p&gt;&#xA;&lt;p&gt;Select the Use Storyboards checkbox. Deselect the Create Document-Based Application and Use Core Data checkboxes. This project is not a document-based application and does not use Core Data.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Xcode 11 Update&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Xcode 11 replaced the Use Storyboards checkbox with an Interface menu. Choose Storyboard from the menu.&lt;/p&gt;&#xA;&lt;p&gt;This project does not use unit tests or UI tests so you can deselect the Include Unit Tests and Include UI Tests checkboxes if you want.&lt;/p&gt;&#xA;&lt;p&gt;Click the Next button. Choose a location to save your project. Click the Create button to finish making the project.&lt;/p&gt;&#xA;&lt;p&gt;After creating the project you should see a list of the project’s files on the left side of the project window. You’re going to work with two files in this tutorial: &lt;code&gt;Main.storyboard&lt;/code&gt;, which contains the user interface, and &lt;code&gt;ViewController.swift&lt;/code&gt;, which contains the source code for the view controller.&lt;/p&gt;&#xA;&lt;h3 id=&#34;buildtheuserinterface&#34;&gt;Build the User Interface&lt;/h3&gt;&#xA;&lt;p&gt;Let’s start by building the user interface. Select the &lt;code&gt;Main.storyboard&lt;/code&gt; file to open it. The user interface for this project has two items: a label to display the random number and a button to click to generate the random number.&lt;/p&gt;&#xA;&lt;p&gt;Drag a label and a button from the object library to the view controller scene. If you’re using Xcode 10 or later, the button to access the object library is on the right side of the project window toolbar.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode10ObjectLibraryHighlighted.png&#34; alt=&#34;Xcode object library&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you’re using an earlier version of Xcode, the object library is in the lower right portion of the project window.&lt;/p&gt;&#xA;&lt;h4 id=&#34;configurethelabel&#34;&gt;Configure the Label&lt;/h4&gt;&#xA;&lt;p&gt;The label you added can use some configuration so it looks better. You’re going to perform the following configurations:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Change the label’s text&lt;/li&gt;&#xA;&lt;li&gt;Center the text&lt;/li&gt;&#xA;&lt;li&gt;Increase the size of the label’s text&lt;/li&gt;&#xA;&lt;li&gt;Resize the label&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;To configure the label select it in the canvas and open the attributes inspector.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/LabelAttributesInspector.png&#34; alt=&#34;label attributes inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter the text &lt;code&gt;0&lt;/code&gt; in the Title text field. Center the text from the Alignment segmented control by clicking the second button.&lt;/p&gt;&#xA;&lt;p&gt;Use the steppers (up and down arrows) next to the Font text field to increase the size of the text to 36 points.&lt;/p&gt;&#xA;&lt;p&gt;Resize the label if you need to so it’s big enough to show two digits with the larger text. Select the label in the canvas to resize the label.&lt;/p&gt;&#xA;&lt;h3 id=&#34;configurethebutton&#34;&gt;Configure the Button&lt;/h3&gt;&#xA;&lt;p&gt;The button has the text &lt;code&gt;Button&lt;/code&gt;. Change the text to &lt;code&gt;Show Number&lt;/code&gt; from the attributes inspector or by double-clicking the button in the canvas. The user interface should look similar to the following when you’re finished:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/FinalUserInterface.png&#34; alt=&#34;final user interface&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;createoutlets&#34;&gt;Create Outlets&lt;/h3&gt;&#xA;&lt;p&gt;Now that you created the user interface, you want to access the label and button in your code. Create outlets so you can do this. Outlets are variables in your code that hold items in your project’s storyboards and xib files.&lt;/p&gt;&#xA;&lt;p&gt;The first step to creating an outlet is to open the assistant editor so the storyboard and source code file are both open. Choose View &amp;gt; Assistant Editor &amp;gt; Show Assistant Editor to open the assistant editor. Open the file &lt;code&gt;Main.storyboard&lt;/code&gt; in one editor and the file &lt;code&gt;ViewController.swift&lt;/code&gt; in the other editor.&lt;/p&gt;&#xA;&lt;p&gt;Select the button in the storyboard. Hold down the Control key and drag to the &lt;code&gt;ViewController.swift&lt;/code&gt; file. When the mouse cursor is inside the definition of the &lt;code&gt;ViewController&lt;/code&gt; class, you should see the text &lt;code&gt;Insert Outlet or Action&lt;/code&gt;. When you see that text you can let go of the mouse button. A popover like the following will open:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreateOutlet.png&#34; alt=&#34;create outlet&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Enter a name for the outlet in the Name text field. Notice how Xcode knows the type is &lt;code&gt;NSButton&lt;/code&gt;. Click the Connect button to finish creating the outlet.&lt;/p&gt;&#xA;&lt;p&gt;Repeat the process for the label. Select it and control-drag to the &lt;code&gt;ViewController.swift&lt;/code&gt; file. This time you’ll notice the type is &lt;code&gt;NSTextField&lt;/code&gt; instead of &lt;code&gt;NSButton&lt;/code&gt;. Labels in Mac apps are text fields and not their own special class like they are in iOS. After creating the outlets, the code should look similar to the following:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ConnectedOutlets.png&#34; alt=&#34;connected outlets&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Make sure the outlets are connected with filled-in circles like they are on the left side of the screenshot. If the outlets aren’t connected, the app will crash when you try to access the outlets.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createanaction&#34;&gt;Create an Action&lt;/h3&gt;&#xA;&lt;p&gt;When someone clicks the button, the app should generate a random number and display it. Create an action so you can add the code to generate the random number and display it. An action is a function that is connected to an item in your user interface. Clicking on the item calls the action.&lt;/p&gt;&#xA;&lt;p&gt;Creating an action is similar to creating an outlet. Select the button and control-drag to the &lt;code&gt;ViewController.swift&lt;/code&gt; file. When you see the &lt;code&gt;Insert Outlet or Action&lt;/code&gt;, let go of the mouse button to open a popover.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreateAction.png&#34; alt=&#34;create actopm&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The connection is now an action. Enter the name in the Name text field. The Type combo box determines the data type of the action’s sender. For this project all you care about is the button was clicked so you can stick with &lt;code&gt;Any&lt;/code&gt;, which can be any type. If you needed to access the button’s title, you would choose &lt;code&gt;NSButton&lt;/code&gt; from the Type combo box. Click the Connect button to create the action, which should look similar to the following:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/ConnectedAction.png&#34; alt=&#34;connected action&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Make sure the action is connected on the left side of the editor or nothing will happen when you click the button.&lt;/p&gt;&#xA;&lt;h3 id=&#34;writethecode&#34;&gt;Write the Code&lt;/h3&gt;&#xA;&lt;p&gt;Now it’s time to write some code. There are two functions you need to write. The first function generates a random number. The second function updates the label with the random number.&lt;/p&gt;&#xA;&lt;p&gt;The following function generates a random number:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;generateRandomNumber&lt;/span&gt;() -&amp;gt; Int {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; minValue = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; maxValue = &lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Int.random(&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;: minValue...maxValue)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first two lines of code define the range for the random number, 0–99. The last line of code generates a random integer in the range I defined. I could have reduced this function to one line,&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Int.random(&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0.&lt;/span&gt;..&lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But I didn’t want to hardcode the values so I created the two constants for the minimum and maximum values.&lt;/p&gt;&#xA;&lt;p&gt;The following function updates the label with the generated random number:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateLabel&lt;/span&gt;(value: Int) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  valueLabel.stringValue = value.description&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The code sets the label’s text to the value of the number I passed to the function. The &lt;code&gt;description&lt;/code&gt; property holds the string representation of the number so it can be displayed in the label.&lt;/p&gt;&#xA;&lt;p&gt;The last thing to do is to call the two functions in the &lt;code&gt;showRandomNumber&lt;/code&gt; action. If you don’t add the code to the action, nothing will happen when you click the button.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@IBAction&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;showRandomNumber&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; sender: Any) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; randomValue = generateRandomNumber()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  updateLabel(value: randomValue)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;&#xA;&lt;p&gt;Click the Play button in the project window toolbar to build and run the project. When you click the Show Number button, a new number appears above the button.&lt;/p&gt;&#xA;&lt;p&gt;I have &lt;a href=&#34;https://github.com/SwiftDevJournal/RandomNumberGenerator&#34;&gt;the project on GitHub&lt;/a&gt; if you run into any problems.&lt;/p&gt;&#xA;&lt;p&gt;If you’re looking to build on this project, I have a few suggestions.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Try creating the project with a xib file instead of a storyboard. Deselect the Use Storyboards checkbox when creating the project. You’ll be using the &lt;code&gt;AppDelegate.swift&lt;/code&gt; file instead of &lt;code&gt;ViewController.swift&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Add arguments to the &lt;code&gt;generateRandomNumber&lt;/code&gt; function for the minimum and maximum values so you can specify the minimum and maximum values for the random number generator.&lt;/li&gt;&#xA;&lt;li&gt;Add text fields to the user interface so people can specify the minimum and maximum values for the random number generator.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Core Data Code Generation</title>
      <link>https://swiftdevjournal.com/core-data-code-generation/</link>
      <pubDate>Tue, 06 Nov 2018 05:01:18 +0000</pubDate>
      <guid>https://swiftdevjournal.com/core-data-code-generation/</guid>
      <description>&lt;p&gt;Starting with Xcode 8, you can let Xcode generate the code for your Core Data entities. Access an entity’s code generation options by selecting the entity and opening the data model inspector.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode8CoreDataCodeGenMenu.png&#34; alt=&#34;Xcode Core Data code gen menu&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The Codegen menu is where you specify the code generation for the entity. There are three code generation options.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Choosing Manual/None tells Xcode not to generate code for the entity. You must create the class for the entity by creating a new file or by choosing Editor &amp;gt; Create NSManagedObject Subclass.&lt;/li&gt;&#xA;&lt;li&gt;Choosing Class Definition tells Xcode to create the entity’s class files when you build the project.&lt;/li&gt;&#xA;&lt;li&gt;Choosing Category/Extension tells Xcode to create a Swift class extension for the entity when you build the project. The class extension has accessors for the entity’s attributes.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;wherearethesourcecodefiles&#34;&gt;Where are the Source Code Files?&lt;/h3&gt;&#xA;&lt;p&gt;If you choose Class Definition or Category/Extension from the Codegen menu, you’ll notice there are no source code files for the entities in the project navigator. Where are the files?&lt;/p&gt;&#xA;&lt;p&gt;The source code files are in the project’s derived data location. You’re not meant to access and edit the source code files Xcode creates for your Core Data entities. The point of Xcode creating the files is to automatically update the files when you make changes to the data model.&lt;/p&gt;&#xA;&lt;p&gt;What do you do if you want to add methods to your Core Data entities? Create Swift class extension files for your entities and add your methods there.&lt;/p&gt;&#xA;&lt;h3 id=&#34;duplicateclasses&#34;&gt;Duplicate Classes&lt;/h3&gt;&#xA;&lt;p&gt;When you create a new Xcode project that uses Core Data, the code generation is initially set to Class Definition. If you manually add class files for your entities, your project won’t build because you have two versions of each class, the one you manually created and the one Xcode creates. This issue can be tough to find because you can’t see the Xcode-created class files in the project navigator.&lt;/p&gt;&#xA;&lt;p&gt;There are two ways to deal with the duplicate class problem. The first way is to remove the class files you added to the project and let Xcode create the classes for you. The second way is to switch to manual code generation by choosing Manual/None from the Codegen menu.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whichcodegenerationoptionshouldyouchoose&#34;&gt;Which Code Generation Option Should You Choose?&lt;/h3&gt;&#xA;&lt;p&gt;Choose manual code generation if you’re using version control in your project. By writing the entity’s code yourself, you can track the changes in your version control system and go back if you make a mistake.&lt;/p&gt;&#xA;&lt;p&gt;Choose the Class Definition code generation option if you don’t want to worry about keeping the data model and code in sync. When you make changes to the data model, you don’t have to worry about updating the code if you choose Class Definition. Xcode updates the code for you.&lt;/p&gt;&#xA;&lt;p&gt;Choose the Category/Extension code generation option if you need more control over the class hierarchy. If you choose the Class Definition code generation option or choose Editor &amp;gt; Create NSManagedObject Subclass to generate your classes manually, Xcode assumes the entity and class hierarchies are the same. If you want a different class hierarchy for your data model, choose the Category/Extension code generation option.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Creating Document-Based iOS Apps Part 2: Make a Text Editor</title>
      <link>https://swiftdevjournal.com/creating-document-based-ios-apps-part-2-make-a-text-editor/</link>
      <pubDate>Fri, 26 Oct 2018 04:13:07 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-document-based-ios-apps-part-2-make-a-text-editor/</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://swiftdevjournal.com/creating-document-based-ios-apps-part-1/&#34;&gt;Part 1 of this tutorial&lt;/a&gt;, you learned the concepts of creating an iOS document-based app. In Part 2 of the tutorial, you will put those concepts into practice by building a simple rich text editor. You must be running Xcode 9 or later to follow along, as Apple added the document-based app project template in Xcode 9.&lt;/p&gt;&#xA;&lt;p&gt;If you haven’t read &lt;a href=&#34;https://swiftdevjournal.com/creating-document-based-ios-apps-part-1/&#34;&gt;Part 1 of the tutorial&lt;/a&gt;, you should do so before you read this tutorial. The first part explains some higher-level concepts that this part glosses over.&lt;/p&gt;&#xA;&lt;h3 id=&#34;createtheproject&#34;&gt;Create The Project&lt;/h3&gt;&#xA;&lt;p&gt;Let’s start by creating the project. Open Xcode and choose File &amp;gt; New &amp;gt; Project. The New Project Assistant opens.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreateProjectStep1.png&#34; alt=&#34;create project step 1&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the iOS button at the top of the window. Select Document Based App. Click the Next button to move to the next step.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreateProjectStep2Cropped.png&#34; alt=&#34;create project step 2&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Name the project in the Product Name text field. Choose your iOS developer profile from the Team menu. Enter your company name or your name in the Organization Name text field. Use that name to fill in the organization identifier. The organization identifier usually takes the form &lt;code&gt;com.CompanyName&lt;/code&gt;. This site is called Swift Dev Journal so choose Swift from the Language menu. Click the Next button to choose a location to save the project.&lt;/p&gt;&#xA;&lt;p&gt;If you look at the project navigator on the left side of the project window, you should see Swift files for the document browser view controller, the document view controller, and the document. You should also see a storyboard. Those are the files you are going to use in the project.&lt;/p&gt;&#xA;&lt;h3 id=&#34;buildtheuserinterface&#34;&gt;Build the User Interface&lt;/h3&gt;&#xA;&lt;p&gt;Now that you created the project, the next step is to build the user interface, which mostly consists of a text view. Select the &lt;code&gt;Main.storyboard&lt;/code&gt; file from the project navigator to open it. The storyboard has two scenes: one for the document browser view controller and one for the document view controller. You’re going to lay out the user interface in the document view controller. Apple creates the document browser user interface for you.&lt;/p&gt;&#xA;&lt;p&gt;You’re going to perform the following tasks to build the user interface:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Remove most of the user interface in the document view controller.&lt;/li&gt;&#xA;&lt;li&gt;Add a text view to the document view controller scene.&lt;/li&gt;&#xA;&lt;li&gt;Configure the text view so you’re editing rich text instead of plain text.&lt;/li&gt;&#xA;&lt;li&gt;Add constraints to the Done button so it’s centered on all iOS devices.&lt;/li&gt;&#xA;&lt;li&gt;Add constraints to the text view so the text isn’t on the edges of the screen.&lt;/li&gt;&#xA;&lt;li&gt;Create an outlet for the text view and connect the outlet so you can access the text view in your code.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;removemostoftheexistinguserinterface&#34;&gt;Remove Most of the Existing User Interface&lt;/h4&gt;&#xA;&lt;p&gt;The document view controller looks like the following initially:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DocumentViewControllerAtStart.png&#34; alt=&#34;document view controller at start&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Keep the Done button so people can go back to the document browser when they’re finished editing a document. Move the Done button out of the stack view and place it at the top center of the screen. After moving the Done button out of the stack view, delete the stack view.&lt;/p&gt;&#xA;&lt;h4 id=&#34;addatextview&#34;&gt;Add a Text View&lt;/h4&gt;&#xA;&lt;p&gt;To add a text view, select the text view element from the object library and drag it to the document view controller. If you can’t find the object library, remember that Apple moved the object library in Xcode 10. The button to open the object library is on the right side of the toolbar.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode10LibraryButtonHighlighted.png&#34; alt=&#34;Xcode library button&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Place the text view below the Done button and have it fill the rest of the view. The document view controller scene should look similar to the following screenshot:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DocumentViewControllerAfterAddingTextView.png&#34; alt=&#34;document view controller after adding text view&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;configurethetextview&#34;&gt;Configure the Text View&lt;/h4&gt;&#xA;&lt;p&gt;Select the text view and open the attributes inspector. Choose Attributed from the Text menu so the text view shows rich text instead of plain text. You can also remove the &lt;code&gt;Lorem ipsum&lt;/code&gt; text if you want. Select the Allows Editing Attributes checkbox.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/TextViewAttributesInspector.png&#34; alt=&#34;text view attributes inspector&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Make sure the Editable checkbox is also selected. A text editor that doesn’t let you edit text is not much fun to use.&lt;/p&gt;&#xA;&lt;h4 id=&#34;addconstraintsforthedonebutton&#34;&gt;Add Constraints for the Done Button&lt;/h4&gt;&#xA;&lt;p&gt;Add a constraint to center the Done button horizontally at the top of the view so that it’s centered on all iOS devices. Select the Done button. Click the Add Constraints button to open a popover to add an alignment constraint.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DoneButtonConstraint.png&#34; alt=&#34;Done button constraint&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Select the Horizontally in Container checkbox. Click the Add 1 Constraint button at the bottom of the popover to add the constraint.&lt;/p&gt;&#xA;&lt;h4 id=&#34;addconstraintsforthetextview&#34;&gt;Add Constraints for the Text View&lt;/h4&gt;&#xA;&lt;p&gt;The container for the text view fills the entire view by default. This means the text you type is pushed against the left edge of the text view. Add some constraints to add some padding.&lt;/p&gt;&#xA;&lt;p&gt;Select the text view. Click the Add Constraints button to open a popover to add new constraints.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/TextViewConstraints.png&#34; alt=&#34;text view constraints&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the four struts surrounding the square at the top of the popover to add some spacing for the text view. Enter spacing values in the text fields. I added 16 points of spacing to the left and right edges and added 10 points of spacing for the top and bottom edges. Click the Add 4 Constraints button at the bottom of the popover to finish adding the constraints.&lt;/p&gt;&#xA;&lt;h4 id=&#34;createandconnectthetextviewoutlet&#34;&gt;Create and Connect the Text View Outlet&lt;/h4&gt;&#xA;&lt;p&gt;To be able to access the text view in your code, you must add an outlet for the text view in your code and connect the text view in the storyboard to the outlet. Add the following property to the &lt;code&gt;DocumentViewController&lt;/code&gt; class to create an outlet:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;@IBOutlet&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;weak&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; textView: UITextView!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now connect the text view in the storyboard to this outlet. Open the assistant editor (choose View &amp;gt; Assistant Editor &amp;gt; Show Assistant Editor) so the source code file and storyboard are both open. Select the text view in the storyboard, hold down the Control key, and drag it to the outlet to make the connection.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingthedocument&#34;&gt;Creating the Document&lt;/h3&gt;&#xA;&lt;p&gt;If you run the project at this point, you’ll notice that tapping the Create Document button does nothing. To create a new document when someone taps the Create Document button, you must do the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Add an empty document file to your project with the same file extension as your document.&lt;/li&gt;&#xA;&lt;li&gt;Edit the document type in Xcode.&lt;/li&gt;&#xA;&lt;li&gt;Add code to load the empty document in the document browser view controller.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you were creating a new document type, you would also have to add an exported UTI for the document. But this app saves RTF files so you don’t need to add an exported UTI.&lt;/p&gt;&#xA;&lt;h4 id=&#34;addanemptydocumentfile&#34;&gt;Add an Empty Document File&lt;/h4&gt;&#xA;&lt;p&gt;Fortunately Xcode has a RTF file template to use as the empty document file. To add an empty RTF file to the project, choose File &amp;gt; New &amp;gt; File. The Rich Text File is in the Resource section under iOS.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreateRichTextFile.png&#34; alt=&#34;create rich text file&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Name the file. I named the file &lt;code&gt;New Document&lt;/code&gt;. You can choose a different name if you want, but remember the name.&lt;/p&gt;&#xA;&lt;h4 id=&#34;editthedocumenttype&#34;&gt;Edit the Document Type&lt;/h4&gt;&#xA;&lt;p&gt;Select the project from the project navigator to open the project editor. Select the app target from the left side of the project editor. Click the Info button at the top of the project editor to access the document types. Click the disclosure triangle next to Document Types.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DocumentTypes.png&#34; alt=&#34;document types&#34;&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Enter &lt;code&gt;RTF&lt;/code&gt; in the Name text field.&lt;/li&gt;&#xA;&lt;li&gt;Enter &lt;code&gt;public.rtf&lt;/code&gt; in the Types text field. &lt;code&gt;public.rtf&lt;/code&gt; is the standard UTI (Uniform Type Identifier) for RTF files.&lt;/li&gt;&#xA;&lt;li&gt;Set the &lt;code&gt;CFBundleTypeRole&lt;/code&gt; key’s value to &lt;code&gt;Editor&lt;/code&gt; so people will be able to edit RTF files in the text editor.&lt;/li&gt;&#xA;&lt;li&gt;Set the &lt;code&gt;LSHandlerRank&lt;/code&gt; key’s value to &lt;code&gt;Alternate&lt;/code&gt;. This will let people edit RTF files in the app without forcing them to use the app to edit all RTF files.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h4 id=&#34;loadtheemptydocument&#34;&gt;Load the Empty Document&lt;/h4&gt;&#xA;&lt;p&gt;Open the &lt;code&gt;DocumentBrowserViewController.swift&lt;/code&gt; file and go to the &lt;code&gt;didRequestDocumentCreationWithHandler&lt;/code&gt; function. You should see the following line of code at the start of the function:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; newDocumentURL: URL? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Change this line of code so it retrieves the empty document file you added to the project.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; newDocumentURL = Bundle.main.url(forResource: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;New Document&amp;#34;&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  withExtension: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rtf&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Make sure the name of the resource matches the name of the empty document file you added to the project. If the names don’t match, the new document won’t be created.&lt;/p&gt;&#xA;&lt;p&gt;There’s one more change to make to the code.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; newDocumentURL &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;importHandler(newDocumentURL, .move)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;importHandler(&lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, .&lt;span style=&#34;color:#66d9ef&#34;&gt;none&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There’s a problem with the code inside the &lt;code&gt;if&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;importHandler(newDocumentURL, .move)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you keep this code, your app will crash the second time you create a document because the empty document file was moved out of the app bundle when you created the first document. When you try to load the empty document file the second time, the app can’t find it in the app bundle, causing a crash. You must copy the file from the app bundle to create multiple documents without crashing.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;importHandler(newDocumentURL, .copy)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;updatedocumentwhentextviewchanges&#34;&gt;Update Document When Text View Changes&lt;/h3&gt;&#xA;&lt;p&gt;The user interface consisting mainly of a text view has a potential problem. If you wait for the person using the app to stop editing to update the document contents and save, you won’t be updating and saving until the person taps the Done button. You run the risk of losing data.&lt;/p&gt;&#xA;&lt;p&gt;For this project you’re going to update the document’s data to match the text view contents when the text view’s contents change. This behavior is not the most efficient, but it minimizes the risk of losing data.&lt;/p&gt;&#xA;&lt;p&gt;Start by adding the following property to the &lt;code&gt;Document&lt;/code&gt; class that stores the document’s text:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; text: NSAttributedString? = &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now it’s time to write some code to update the document when the text view’s contents change. Add the following function to the document view controller:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;textViewDidChange&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; textView: UITextView) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  document?.text = textView.attributedText&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;document?.updateChangeCount(.done)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the contents of the text view change, change the document’s &lt;code&gt;text&lt;/code&gt; property so it holds the text view’s contents. Update the change count for the document to trigger autosaving for the document.&lt;/p&gt;&#xA;&lt;h3 id=&#34;savethedocument&#34;&gt;Save the Document&lt;/h3&gt;&#xA;&lt;p&gt;To save the document, implement the function &lt;code&gt;contentsForType&lt;/code&gt; in the &lt;code&gt;Document&lt;/code&gt; class.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;contents&lt;/span&gt;(forType typeName: String) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; -&amp;gt; Any {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; textToSave = text &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Data() }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; NSKeyedArchiver.archivedData(withRootObject: textToSave)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first line of code makes sure the &lt;code&gt;text&lt;/code&gt; property is not nil before saving. The second line grabs the document’s text and calls the &lt;code&gt;NSKeyedArchiver&lt;/code&gt; method &lt;code&gt;archivedData&lt;/code&gt; to save the text.&lt;/p&gt;&#xA;&lt;h3 id=&#34;openthedocument&#34;&gt;Open the Document&lt;/h3&gt;&#xA;&lt;p&gt;To open the document, start by implementing the &lt;code&gt;load&lt;/code&gt; function in the &lt;code&gt;Document&lt;/code&gt; class.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt;(fromContents contents: Any, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ofType typeName: String?) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// Load your document from contents&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; data = contents &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? Data &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;guard&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; fileContents = NSKeyedUnarchiver.unarchiveObject(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    with: data) &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? NSAttributedString &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  text = fileContents&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first line of code in the function makes sure the file has suitable data to load. The second line loads the document text from the file by calling the &lt;code&gt;NSKeyedUnarchiver&lt;/code&gt; method &lt;code&gt;unarchiveObject&lt;/code&gt;. The last line sets the document’s &lt;code&gt;text&lt;/code&gt; property to the text you loaded from the file.&lt;/p&gt;&#xA;&lt;p&gt;Now you must set the text view’s contents to the document’s text you just loaded. The document view controller’s &lt;code&gt;viewDidAppear&lt;/code&gt; method has a block of code to open the file. If the open is successful, set the text view’s attributed text to the document’s text.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;document?.open(completionHandler: { (success) &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; success {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// Display the content of the document.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.textView.attributedText = &lt;span style=&#34;color:#66d9ef&#34;&gt;self&lt;/span&gt;.document?.text&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Make sure to handle the failed import appropriately.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;&#xA;&lt;p&gt;I put &lt;a href=&#34;https://github.com/SwiftDevJournal/iOSRichTextEditor&#34;&gt;this project on GitHub&lt;/a&gt; for you to look at if you run into problems. If you look at the GitHub project, you can see how to scroll the text view when the onscreen keyboard appears and disappears. Scrolling the text view is important for a text editor so the keyboard doesn’t block what you’re typing, but scrolling the text view doesn’t involve document-based apps so I didn’t write about it in the article.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Creating Document-Based iOS Apps Part 1</title>
      <link>https://swiftdevjournal.com/creating-document-based-ios-apps-part-1/</link>
      <pubDate>Thu, 25 Oct 2018 18:59:00 +0000</pubDate>
      <guid>https://swiftdevjournal.com/creating-document-based-ios-apps-part-1/</guid>
      <description>&lt;p&gt;iOS support for document-based apps opens up new categories of apps for you to develop. Want to develop screenwriting software? A video editing app? A level editor for a game? By making a document-based app you can make iOS versions of these types of apps.&lt;/p&gt;&#xA;&lt;p&gt;In iOS 11 Apple simplified creating and opening documents, making it easier for developers to create document-based apps. Unfortunately Apple did not update their documentation to reflect these changes.&lt;/p&gt;&#xA;&lt;p&gt;This article helps document those changes. To make things more manageable, I divided it into two parts. This part covers the higher-level concepts. The second part walks you through creating a rich text editor.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whataredocument-basedapps&#34;&gt;What Are Document-Based Apps?&lt;/h3&gt;&#xA;&lt;p&gt;Document-based apps let people create documents that they can share. Examples of document-based apps include text editors, spreadsheets, and image editors. The document is the text, spreadsheet, or image that you’re editing.&lt;/p&gt;&#xA;&lt;p&gt;Document-based apps are more common on Macs than on iOS. But by learning how to create document-based apps in iOS, you can build powerful apps that used to require a Mac to run.&lt;/p&gt;&#xA;&lt;h3 id=&#34;theclasses&#34;&gt;The Classes&lt;/h3&gt;&#xA;&lt;p&gt;There are two classes to study to develop document-based apps. The first class is &lt;code&gt;UIDocumentBrowserViewController&lt;/code&gt;, which controls the document browser.&lt;/p&gt;&#xA;&lt;p&gt;The document browser is where someone using your app creates and opens documents. The following screenshot shows what the document browser looks like initially:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DocumentBrowserForNewProject.png&#34; alt=&#34;document browser for new project&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The second class is &lt;code&gt;UIDocument&lt;/code&gt;, which represents the document. When you create a document-based app project, Xcode includes a &lt;code&gt;UIDocument&lt;/code&gt; subclass for you. You use this class to store any data properties related to your document.&lt;/p&gt;&#xA;&lt;h3 id=&#34;yourtasks&#34;&gt;Your Tasks&lt;/h3&gt;&#xA;&lt;p&gt;You have to perform the following tasks to develop an iOS document-based app:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Create a document-based app project in Xcode.&lt;/li&gt;&#xA;&lt;li&gt;Set up your document type to create new documents.&lt;/li&gt;&#xA;&lt;li&gt;Implement delegate functions in the document browser view controller to handle creating new documents and selecting documents from the document browser.&lt;/li&gt;&#xA;&lt;li&gt;Save the document.&lt;/li&gt;&#xA;&lt;li&gt;Open the document.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;It looks like a lot of work to make a document-based app, but there’s much less code to write than you think. In the project I wrote for the second part of this article, I wrote less than ten lines of code to implement the delegate functions, save the document, and open the document. Apple’s document-based app project template does a lot of work for you.&lt;/p&gt;&#xA;&lt;h3 id=&#34;creatingadocument-basedappprojectinxcode&#34;&gt;Creating a Document-Based App Project in Xcode&lt;/h3&gt;&#xA;&lt;p&gt;Creating a document-based app project in Xcode gives you a document browser view controller, a view controller for the document, and a &lt;code&gt;UIDocument&lt;/code&gt; subclass.&lt;/p&gt;&#xA;&lt;h3 id=&#34;settingupyourdocumenttypetocreatenewdocuments&#34;&gt;Setting Up Your Document Type to Create New Documents&lt;/h3&gt;&#xA;&lt;p&gt;There’s a surprising amount of work involved in creating a new document when someone taps the Create Document button in the document browser. You must perform the following tasks:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Set up the document type.&lt;/li&gt;&#xA;&lt;li&gt;Supply a blank file to create documents.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you are creating a brand new document type, you must also add an exported UTI for the document. UTI stands for Uniform Type Identifier. A UTI uniquely identifies a file type. The exported UTI lets the operating system and other apps know about the existence of your file type.&lt;/p&gt;&#xA;&lt;h4 id=&#34;setupthedocumenttype&#34;&gt;Set Up the Document Type&lt;/h4&gt;&#xA;&lt;p&gt;When you create a document-based app project, Xcode creates a document type for you. Use Xcode’s project editor to configure the document type. Start by selecting your project from the project navigator to open the project editor and selecting your app target from the left side of the project editor. Click the Info button at the top of the project editor to access the Document Types section.&lt;/p&gt;&#xA;&lt;p&gt;Enter the UTIs for your document type in the Types text field. If you are creating a new file type, the UTI should take the form &lt;code&gt;com.CompanyName.FileType&lt;/code&gt;. If you are using an existing file type, supply its UTI. Suppose you are developing a plain text editor. The UTI for your document would be &lt;code&gt;public.plain-text&lt;/code&gt;. Apple has &lt;a href=&#34;https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html#//apple_ref/doc/uid/TP40009259-SW1&#34;&gt;a list of system-declared UTIs&lt;/a&gt;, but it’s not being actively maintained.&lt;/p&gt;&#xA;&lt;p&gt;The Document Types section has a subsection called Additional document type properties. You must add two document type properties. The first property has the key &lt;code&gt;CFBundleTypeRole&lt;/code&gt;. Its type is &lt;code&gt;String&lt;/code&gt;. Its value should be &lt;code&gt;Editor&lt;/code&gt; if you want people to edit your documents.&lt;/p&gt;&#xA;&lt;p&gt;The second property has the key &lt;code&gt;LSHandlerRank&lt;/code&gt;. Its type is &lt;code&gt;String&lt;/code&gt;. For new file types, the value should be &lt;code&gt;Owner&lt;/code&gt; because your app owns the file type. For existing file types the value should be &lt;code&gt;Alternate&lt;/code&gt;. The alternate handler rank allows your app to edit files of the file type but keeps your app from being the default app to edit files of that type. Suppose you’re making an image editor that lets people edit PNG files. By making your app the alternate editor, you can edit PNG files in your app without forcing people to use your app to edit all PNG files.&lt;/p&gt;&#xA;&lt;h4 id=&#34;supplyablankfiletocreatedocuments&#34;&gt;Supply a Blank File to Create Documents&lt;/h4&gt;&#xA;&lt;p&gt;You need to create a blank file when someone chooses to create a new document. Otherwise tapping the Create Document button does nothing. The easiest way to create a blank file is to add an empty file to your project whose file extension matches the name of your document’s file extension. Your app will load this file from the app bundle when someone creates a new document.&lt;/p&gt;&#xA;&lt;h4 id=&#34;addanexporteduti&#34;&gt;Add an Exported UTI&lt;/h4&gt;&#xA;&lt;p&gt;If you are creating a new document type, you must add an exported UTI for the document type. The exported UTI lets the operating system and other apps know of the existence of your new file type. Exported UTIs are in the same section as document types in Xcode’s project editor.&lt;/p&gt;&#xA;&lt;p&gt;Enter your document’s UTI in the Identifier text field. The UTI should take the form &lt;code&gt;com.CompanyName.FileType&lt;/code&gt;. Enter any additional UTIs your exported UTI supports in the Conforms To text field. If your document saves its contents in a file package instead of a single file, you would add the UTI &lt;code&gt;com.apple.package&lt;/code&gt; in the Conforms To text field.&lt;/p&gt;&#xA;&lt;p&gt;You also must add an additional exported UTI property. The key is &lt;code&gt;UTTypeTagSpecification&lt;/code&gt;, and its type is &lt;code&gt;Dictionary&lt;/code&gt;. You must create two dictionary items. The first item has the key &lt;code&gt;public.mime-type&lt;/code&gt;. Its type is &lt;code&gt;String&lt;/code&gt;. Its value is the UTI for your document type.&lt;/p&gt;&#xA;&lt;p&gt;The second item has the key &lt;code&gt;public.filename-extension&lt;/code&gt;. Its type is &lt;code&gt;String&lt;/code&gt;. Its value is the file extension for your document. Do not add a dot in front of the file extension.&lt;/p&gt;&#xA;&lt;h3 id=&#34;documentbrowserdelegatefunctions&#34;&gt;Document Browser Delegate Functions&lt;/h3&gt;&#xA;&lt;p&gt;Handling creating a new document requires you to implement two delegate functions in the document browser view controller: &lt;code&gt;didRequestDocumentCreationWithHandler&lt;/code&gt; and &lt;code&gt;didImportDocumentAt&lt;/code&gt;. You load the empty document file from the app bundle in &lt;code&gt;didRequestDocumentCreationWithHandler&lt;/code&gt; when someone creates a new document.&lt;/p&gt;&#xA;&lt;p&gt;Fortunately the document browser view controller in Xcode’s document-based app project template provides basic versions of these two delegate functions for you. Unless you’re doing something like Pages, where creating a document opens a template chooser, you won’t have to write much code. In the project for the second part of this article, I had to add one line of code in &lt;code&gt;didRequestDocumentCreationWithHandler&lt;/code&gt; and change one other line of code.&lt;/p&gt;&#xA;&lt;p&gt;Handling selecting a document from the document browser requires you to implement the delegate function &lt;code&gt;didPickDocumentURLs&lt;/code&gt; in the document browser view controller. The document browser view controller provides a basic version for you to use. In the project for the second part of this article, I didn’t have to change anything in &lt;code&gt;didPickDocumentURLs&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;savingdocuments&#34;&gt;Saving Documents&lt;/h3&gt;&#xA;&lt;p&gt;To save a document you must override the &lt;code&gt;contentsOfType&lt;/code&gt; function in the &lt;code&gt;UIDocument&lt;/code&gt; subclass. Xcode’s document-based app project template provides an empty function for you to fill in. In most cases you’ll use the &lt;code&gt;NSKeyedArchiver&lt;/code&gt; class to save the document data.&lt;/p&gt;&#xA;&lt;h3 id=&#34;openingdocuments&#34;&gt;Opening Documents&lt;/h3&gt;&#xA;&lt;p&gt;To open a document you must override the &lt;code&gt;load&lt;/code&gt; function in the &lt;code&gt;UIDocument&lt;/code&gt; subclass. Xcode’s document-based app project template provides an empty function for you to fill in. In most cases you’ll use the &lt;code&gt;NSKeyedUnarchiver&lt;/code&gt; class to read the document data from the file.&lt;/p&gt;&#xA;&lt;h3 id=&#34;ontopart2&#34;&gt;On to Part 2&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://swiftdevjournal.com/creating-document-based-ios-apps-part-2-make-a-text-editor/&#34;&gt;Part 2&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Crashing with Swift Optionals</title>
      <link>https://swiftdevjournal.com/crashing-with-swift-optionals/</link>
      <pubDate>Thu, 18 Oct 2018 17:53:35 +0000</pubDate>
      <guid>https://swiftdevjournal.com/crashing-with-swift-optionals/</guid>
      <description>&lt;p&gt;If you have done any iOS or Mac programming in Swift, you have probably had your app crash with the following message in Xcode’s debugger:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Fatal error: Unexpectedly found nil while unwrapping an Optional value&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you don’t understand this error message, keep reading. In this article you’ll learn what this error message means, common causes of the message, and ways to fix your code so your app stops crashing.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatdoesthemessagemean&#34;&gt;What Does the Message Mean?&lt;/h3&gt;&#xA;&lt;p&gt;Before I can tell you what the error message means, I need to explain Swift optionals. An optional is a data type for a variable where the variable either exists or doesn’t exist, in which case it’s nil. Pretty much anything in Swift can be an optional, including integers, strings, arrays, table views, structs, and classes. The following code shows an example of declaring an optional variable:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; description: String?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A special kind of optional is an implicitly unwrapped optional. While an optional can either exist or not exist, an implicitly unwrapped optional must exist. If an implicitly unwrapped optional is nil and you attempt to use it, the app crashes. The following code shows an example of using an implicitly unwrapped optional:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(description!)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;description&lt;/code&gt; exists, the code will print the description, but if &lt;code&gt;description&lt;/code&gt; is nil, the code crashes.&lt;/p&gt;&#xA;&lt;p&gt;Now to answer the question in the section heading. The error message &lt;code&gt;Fatal error: Unexpectedly found nil while unwrapping an Optional value&lt;/code&gt; is saying the app is implicitly unwrapping a nil optional value. The error is similar to accessing a nil pointer in C, C++, or Objective-C.&lt;/p&gt;&#xA;&lt;h3 id=&#34;whatcausestheerror&#34;&gt;What Causes the Error?&lt;/h3&gt;&#xA;&lt;p&gt;The general cause of the error is having an implicitly unwrapped optional that’s nil. But you’re looking for specific causes. I can think of three common sources of implicitly unwrapped optionals that are nil.&lt;/p&gt;&#xA;&lt;p&gt;The first common source is forgetting to connect the outlets for your user interface elements. Outlets in Interface Builder are usually declared as implicitly unwrapped optionals because you can assume the outlet is going to exist after loading the storyboard or xib file. But if you forget to connect the outlet, the outlet is nil and your app will crash when it tries to use the outlet. The following screenshot shows what a disconnected outlet looks like in Xcode:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/DisconnectedOutlet.png&#34; alt=&#34;disconnected outlet&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The disconnected outlet is the circle above Line 14. A connected outlet has a filled-in circle.&lt;/p&gt;&#xA;&lt;p&gt;The second common source is using &lt;code&gt;as!&lt;/code&gt; to downcast to a specific type. Look at the following code to instantiate a view controller from a storyboard:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; documentViewController = storyBoard.instantiateViewController(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;withIdentifier: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DocumentViewController&amp;#34;&lt;/span&gt;) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;! DocumentViewController&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code will crash in any of the following situations:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I forgot to give the view controller an identifier in the storyboard.&lt;/li&gt;&#xA;&lt;li&gt;The identifier in the storyboard doesn’t match the string in the code.&lt;/li&gt;&#xA;&lt;li&gt;I forgot to set the class of the view controller in the storyboard.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;With implicitly unwrapped optionals it doesn’t take much to cause a crash.&lt;/p&gt;&#xA;&lt;p&gt;The last common source is using implicitly unwrapped optionals in your code. If you see an exclamation point at the end of any of your variable names, you have a potential crash in your code. What doesn’t help matters is when you have a compiler syntax error in your code involving optionals, Xcode’s suggested fix is to make an implicitly unwrapped optional. Following Xcode’s advice makes your code more likely to crash.&lt;/p&gt;&#xA;&lt;h3 id=&#34;howdoyoufixtheerror&#34;&gt;How Do You Fix the Error?&lt;/h3&gt;&#xA;&lt;p&gt;The general fix to avoid these crashes is to avoid using implicitly unwrapped optionals. The following techniques will help you avoid crashes caused by implicitly unwrapped optionals:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Connect your user interface elements to the outlets in your code.&lt;/li&gt;&#xA;&lt;li&gt;Use &lt;code&gt;as?&lt;/code&gt; instead of &lt;code&gt;as!&lt;/code&gt; when downcasting.&lt;/li&gt;&#xA;&lt;li&gt;Use &lt;code&gt;if let&lt;/code&gt; or &lt;code&gt;guard&lt;/code&gt; statements to safely unwrap your optionals.&lt;/li&gt;&#xA;&lt;li&gt;Use the &lt;code&gt;??&lt;/code&gt; operator to provide a default value in case the optional value is nil.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;To connect your user interface elements to your outlets, open Xcode’s assistant editor so your source code file and your storyboard or xib file are both open. Select the user interface element in the storyboard or xib file. Hold the Control key down and drag to the outlet in your code to make the connection.&lt;/p&gt;&#xA;&lt;p&gt;I can demonstrate the last two techniques by fixing the earlier example of instantiating a view controller from the storyboard. Using an &lt;code&gt;if let&lt;/code&gt; statement and &lt;code&gt;as?&lt;/code&gt; to downcast is enough to fix the code. The following code makes sure the view controller has been instantiated, then presents the view controller:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-swift&#34; data-lang=&#34;swift&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; documentViewController = storyBoard.instantiateViewController(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  withIdentifier: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DocumentViewController&amp;#34;&lt;/span&gt;) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt;? DocumentViewController {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  present(documentViewController, animated: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;, completion: &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if I forgot to give the view controller an identifier or misspelled the name of the identifier, the app won’t crash. The app won’t present the view controller, but at least there won’t be a crash.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Putting Your Xcode Project on GitHub, Bitbucket, or GitLab</title>
      <link>https://swiftdevjournal.com/putting-your-xcode-project-on-github-bitbucket-or-gitlab/</link>
      <pubDate>Tue, 09 Oct 2018 19:14:38 +0000</pubDate>
      <guid>https://swiftdevjournal.com/putting-your-xcode-project-on-github-bitbucket-or-gitlab/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com&#34;&gt;GitHub&lt;/a&gt;, &lt;a href=&#34;https://bitbucket.org&#34;&gt;Bitbucket&lt;/a&gt;, and &lt;a href=&#34;https://gitlab.com&#34;&gt;GitLab&lt;/a&gt; simplify working on projects with other people. These sites also provide online backup for your projects in case your computer is damaged or stolen. Starting with Xcode 10 (Xcode 9 for GitHub) you can put your Xcode projects on GitHub, BitBucket, or GitLab without leaving Xcode. This article shows you how.&lt;/p&gt;&#xA;&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;&#xA;&lt;p&gt;You must have an account on GitHub, Bitbucket, or GitLab. Xcode can’t create an online account for you. If you don’t have an account, go to the site you want to use and create an account. GitHub is the most popular place to host projects online, but Bitbucket and GitLab are also fine to use.&lt;/p&gt;&#xA;&lt;p&gt;Your Xcode project must be under version control. The easiest way to place your project under version control is to select the checkbox to create a git repository when you create the project.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/CreateGitRepoNewProject.png&#34; alt=&#34;create git repo for new project&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you have an existing Xcode project that is not under version control, choose Source Control &amp;gt; New Git Repository in Xcode to create a git repository for the project.&lt;/p&gt;&#xA;&lt;h3 id=&#34;addingyouraccounttoxcode&#34;&gt;Adding Your Account to Xcode&lt;/h3&gt;&#xA;&lt;p&gt;Adding your GitHub, Bitbucket, or GitLab account to Xcode isn’t mandatory, but doing so makes things a little easier when you put your project online. Open Xcode’s Account preferences by choosing Xcode &amp;gt; Preferences and clicking the Accounts button in the preference window’s toolbar.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode10AccountsPreferencesHighlighted.png&#34; alt=&#34;Xcode accounts preferences&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Click the Add button to add an account.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode10AddBitbucketAccount.png&#34; alt=&#34;add account&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Choose GitHub to add a GitHub account, Bitbucket Cloud to add a Bitbucket account, and GitLab.com to add a GitLab account. Xcode will ask you for your username and password.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;GitHub requires you to &lt;a href=&#34;https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token&#34;&gt;create a personal access token&lt;/a&gt; and use that instead of a password for authentication.&lt;/p&gt;&#xA;&lt;h3 id=&#34;puttingtheprojectonline&#34;&gt;Putting the Project Online&lt;/h3&gt;&#xA;&lt;p&gt;You’re going to use Xcode’s source control navigator to put the project online. Open the source control navigator by choosing View &amp;gt; Navigators &amp;gt; Show Source Control Navigator or by pressing Cmd–2.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/SourceControlNavigatorAtStart.png&#34; alt=&#34;source control navigator at start&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Newer versions of Xcode have Changes and Repositories buttons at the top of the source control navigator. Click the Repositories button to show the branches in the git repository.&lt;/p&gt;&#xA;&lt;p&gt;Creating a remote branch is how you put your project online. Select the Remotes folder, control-click, and choose Create Remote. A sheet like the following will open:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://swiftdevjournal.com/images/Xcode10AddBitbucketRepoHighlighted.png&#34; alt=&#34;create remote branch sheet&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Choose your account from the Account menu. If you did not add your account to Xcode, choose Add an account to add your account. Choosing an account will set the Owner menu to the username for your account.&lt;/p&gt;&#xA;&lt;p&gt;Xcode sets the repository name to the name of the project for you, but you can change it if you want. Xcode has problems with uppercase letters in Bitbucket repository names. Use all lowercase letters if you’re using Bitbucket. If you would like to enter a more detailed description of the project, use the Description text view.&lt;/p&gt;&#xA;&lt;p&gt;Choose the visibility for your project online: private or public.&lt;/p&gt;&#xA;&lt;p&gt;The remote name is initially set to &lt;code&gt;origin&lt;/code&gt;. If you want a different name, enter it in the text field. The most common reason to change the name is hosting your project on multiple sites. Suppose you want to host your project on both GitHub and Bitbucket. To avoid confusion it would make sense to name the GitHub remote &lt;code&gt;github&lt;/code&gt; and the Bitbucket remote &lt;code&gt;bitbucket&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Click the Create button to create the remote branch and place your Xcode project online.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wheretogofromhere&#34;&gt;Where to Go from Here?&lt;/h3&gt;&#xA;&lt;p&gt;Now that your Xcode project is online, you’ll have the option to push your changes online every time you commit.&lt;/p&gt;&#xA;&lt;p&gt;Work on your Xcode project in a local branch. Push your changes to move them to the remote branch on GitHub, Bitbucket, or GitLab.&lt;/p&gt;&#xA;&lt;p&gt;If you want other people to work on your project with you, they can clone your project by choosing Source Control &amp;gt; Clone in Xcode.&lt;/p&gt;&#xA;&lt;h3 id=&#34;wanttolearnmoreaboutversioncontrol&#34;&gt;Want to Learn More About Git?&lt;/h3&gt;&#xA;&lt;p&gt;Check out my &lt;a href=&#34;https://www.swiftdevjournal.com/version-control-book/&#34;&gt;version control book&lt;/a&gt;. It shows you how to do the most common git tasks without leaving Xcode. Some of the material covered in the book includes cloning projects from GitHub, branching, and going back to earlier versions of your project.&lt;/p&gt;&#xA;</description>
    </item>
  </channel>
</rss>
