{
    "version": "https://jsonfeed.org/version/1",
    "title": "Swiftjective-C",
    "description": "Swift, SwiftUI, UIKit, iOS programming, and indie development articles by Jordan Morgan.",
    "home_page_url": "https://swiftjectivec.com/",
    "feed_url": "https://swiftjectivec.com/feed.json",
    "author": {
        "name": "Jordan Morgan", "avatar": "/assets/images/about/headshot.jpeg"},
    "items": [
      {
            "id": "https://swiftjectivec.com/Siri-AI-for-iOS027",
            "url": "https://swiftjectivec.com/Siri-AI-for-iOS027/",
            "title": "iOS 27, Your App, and Siri",
            "content_html": "<p>The dawn of a new Siri (AI) looms in the air. When it ships, the promise of just saying what you want done, and having Siri just…do it, should be realistic. Apple, true to their roots of being masterful storytellers in terms of product, had many examples on tap. “Hey Siri, what was the water bottle I was thinking of getting a few months ago?”, and BAM — Siri went through a mountain of personal context, and found the answer.</p>\n\n<p>That stuff is obvious. But, what about <em>your</em> app?</p>\n\n<p>“Hey Siri, what team did I last make a play for in Elite Hoops?”</p>\n\n<p>How do we do that, what’s involved, and how should you think about Siri and your app over the summer? I <em>think</em> I have a fairly good grasp on it, and I’ll summarize it here. I’m skipping deep dives, and just keeping it to a <a href=\"https://www.reddit.com/r/DunderMifflin/comments/1d8xkz4/what_is_a_rundown/\">rundown</a>.</p>\n\n<section class=\"bg-indigo-50 border-l-8 border-indigo-500 text-gray-800 rounded-md my-10 dark:text-gray-300 dark:bg-gray-600 dark:border-indigo-700 \">\n    <div class=\"px-5 font-mono\">\n        <p class=\"pt-2 md:pt-4\"><span class=\"text-purple-600 dark:text-purple-400\">let</span> concatenatedThoughts = <span class=\"text-red-600\">\"\"\"</span></p>\n        <p class=\"text-gray-600 dark:text-gray-300 text-sm md:text-base\">This is based off of having on seen this <a href=\"https://developer.apple.com/videos/play/wwdc2026/240?\">WWDC session</a>, so I might be missing some context. Though, from what I've seen, this is where the goods are at.</p>\n        <p class=\"pb-2 md:pb-4 text-gray-600 text-base\"><span class=\"text-red-600\">\"\"\"</span></p>\n    </div>\n</section>\n\n<p>First off, the parts involved. The whole process is the same — it’s still app entities for your app’s models, schemas for a particular definition of those if applicable, and a few APIs to make those known to Siri when they are on screen.</p>\n\n<h3 id=\"app-entity\">App Entity</h3>\n<p>First, each of your app’s data models that should participate in Shortcuts, an App Intent, or general system-wide intelligence should hav a lightweight <code class=\"language-plaintext highlighter-rouge\">AppEntity</code> version. This isn’t the same as the model <em>itself</em>, but a lightweight version of it:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">struct</span> <span class=\"kt\">TeamEntity</span><span class=\"p\">:</span> <span class=\"kt\">AppEntity</span> <span class=\"p\">{</span>\n    <span class=\"kd\">static</span> <span class=\"k\">var</span> <span class=\"nv\">defaultQuery</span> <span class=\"o\">=</span> <span class=\"kt\">TeamEntityQuery</span><span class=\"p\">()</span>\n    <span class=\"kd\">static</span> <span class=\"k\">var</span> <span class=\"nv\">typeDisplayRepresentation</span><span class=\"p\">:</span> <span class=\"kt\">TypeDisplayRepresentation</span> <span class=\"o\">=</span> <span class=\"o\">.</span><span class=\"nf\">init</span><span class=\"p\">(</span><span class=\"nv\">stringLiteral</span><span class=\"p\">:</span> <span class=\"s\">\"Team\"</span><span class=\"p\">)</span>\n    \n    <span class=\"k\">var</span> <span class=\"nv\">displayRepresentation</span><span class=\"p\">:</span> <span class=\"kt\">DisplayRepresentation</span> <span class=\"p\">{</span>\n        <span class=\"kt\">DisplayRepresentation</span><span class=\"p\">(</span><span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"</span><span class=\"se\">\\(</span><span class=\"n\">name</span><span class=\"se\">)</span><span class=\"s\">\"</span><span class=\"p\">,</span>\n                              <span class=\"nv\">subtitle</span><span class=\"p\">:</span> <span class=\"s\">\"</span><span class=\"se\">\\(</span><span class=\"n\">rosterSize</span><span class=\"se\">)</span><span class=\"s\"> </span><span class=\"se\">\\(</span><span class=\"n\">rosterSize</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"p\">?</span> <span class=\"s\">\"player\"</span> <span class=\"p\">:</span> <span class=\"s\">\"players\"</span><span class=\"se\">)</span><span class=\"s\">\"</span><span class=\"p\">,</span>\n                              <span class=\"nv\">image</span><span class=\"p\">:</span> <span class=\"kt\">DisplayRepresentation</span><span class=\"o\">.</span><span class=\"kt\">Image</span><span class=\"p\">(</span><span class=\"nv\">data</span><span class=\"p\">:</span> <span class=\"n\">logo</span><span class=\"p\">))</span>\n    <span class=\"p\">}</span>\n    \n    <span class=\"k\">let</span> <span class=\"nv\">id</span><span class=\"p\">:</span> <span class=\"kt\">String</span>\n    \n    <span class=\"kd\">@Property</span><span class=\"p\">(</span><span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"Team Name\"</span><span class=\"p\">)</span>\n    <span class=\"k\">var</span> <span class=\"nv\">name</span><span class=\"p\">:</span> <span class=\"kt\">String</span>\n    \n    <span class=\"kd\">@Property</span><span class=\"p\">(</span><span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"Roster Size\"</span><span class=\"p\">)</span>\n    <span class=\"k\">var</span> <span class=\"nv\">rosterSize</span><span class=\"p\">:</span> <span class=\"kt\">Int</span>\n    \n    <span class=\"kd\">@Property</span><span class=\"p\">(</span><span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"Roster\"</span><span class=\"p\">)</span>\n    <span class=\"k\">var</span> <span class=\"nv\">roster</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"kt\">String</span><span class=\"p\">]</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"surfacing-app-entities\">Surfacing App Entities</h3>\n<p>From there, Siri needs to be able to find them. There are two routes. First, if a network trip is required or otherwise surfacing content takes more work, then you should use <code class=\"language-plaintext highlighter-rouge\">EntityStringQuery</code>:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">extension</span> <span class=\"kt\">TeamEntityQuery</span><span class=\"p\">:</span> <span class=\"kt\">EntityStringQuery</span> <span class=\"p\">{</span>\n    <span class=\"kd\">func</span> <span class=\"nf\">entities</span><span class=\"p\">(</span><span class=\"n\">matching</span> <span class=\"nv\">string</span><span class=\"p\">:</span> <span class=\"kt\">String</span><span class=\"p\">)</span> <span class=\"k\">async</span> <span class=\"k\">throws</span> <span class=\"o\">-&gt;</span> <span class=\"p\">[</span><span class=\"kt\">TeamEntity</span><span class=\"p\">]</span> <span class=\"p\">{</span>\n        <span class=\"kt\">Logs</span><span class=\"o\">.</span><span class=\"n\">appIntents</span><span class=\"o\">.</span><span class=\"nf\">info</span><span class=\"p\">(</span><span class=\"s\">\"TeamEntityQuery: String query for term </span><span class=\"se\">\\(</span><span class=\"n\">string</span><span class=\"se\">)</span><span class=\"s\">\"</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">guard</span> <span class=\"k\">let</span> <span class=\"nv\">dao</span> <span class=\"o\">=</span> <span class=\"kt\">DAO</span><span class=\"o\">.</span><span class=\"n\">readOnly</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n            <span class=\"kt\">Logs</span><span class=\"o\">.</span><span class=\"n\">appIntents</span><span class=\"o\">.</span><span class=\"nf\">info</span><span class=\"p\">(</span><span class=\"s\">\"There is no database available for the intent to read from.\"</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"p\">[]</span>\n        <span class=\"p\">}</span>\n        \n        <span class=\"k\">let</span> <span class=\"nv\">courts</span> <span class=\"o\">=</span> <span class=\"k\">try</span> <span class=\"k\">await</span> <span class=\"n\">dao</span><span class=\"o\">.</span><span class=\"nf\">fetchCourtsBy</span><span class=\"p\">(</span><span class=\"nv\">name</span><span class=\"p\">:</span> <span class=\"n\">string</span><span class=\"p\">)</span>\n        <span class=\"k\">let</span> <span class=\"nv\">entities</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"kt\">TeamEntity</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"k\">try</span> <span class=\"k\">await</span> <span class=\"kt\">TeamEntity</span><span class=\"o\">.</span><span class=\"nf\">fetchData</span><span class=\"p\">(</span><span class=\"nv\">for</span><span class=\"p\">:</span> <span class=\"n\">courts</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">entities</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>More commonly, <code class=\"language-plaintext highlighter-rouge\">IndexedEntity</code> is the best path forward. The system automatically indexes this content for you. In fact, most cases just need you to declare conformance:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">extension</span> <span class=\"kt\">TeamEntity</span><span class=\"p\">:</span> <span class=\"kt\">IndexedEntity</span> <span class=\"p\">{}</span>\n</code></pre></div></div>\n\n<p>In fact, you can simply conform to <code class=\"language-plaintext highlighter-rouge\">IndexedEntity</code> directly as opposed to <code class=\"language-plaintext highlighter-rouge\">AppEntity</code>. Once you do that, you can identify which parts should be index for search, too, with <code class=\"language-plaintext highlighter-rouge\">@Property(indexingKey:)</code>.</p>\n\n<p>This is, however, where I’m not entirely sure of the relationships between Siri and your app. If you fill type <code class=\"language-plaintext highlighter-rouge\">@Property(indexingKey: \\.)</code> — you’ll get a list of autocompleted things you can use here. I believe all of these tie into a predefined App Schema, and the properties within them. So, what if your app doesn’t fit into those? I’m not sure, but I don’t think you can use indexing keys in that case.</p>\n\n<h3 id=\"app-schemas\">App Schemas</h3>\n<p>Speaking of App Schemas, and their associated domains, are basically <em>juiced up</em> App Intents. Apple has already trained Siri to the moon and back over them, it’ll understand context better, and participate in follow up questions and everything else in-between. They’ve done the work for you. So, if you app fits into one of these schemas, absolutely use it.</p>\n\n<p>You do so by using a property wrapper above your entity declaration:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">@AppEntity</span><span class=\"p\">(</span><span class=\"nv\">schema</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"n\">messages</span><span class=\"o\">.</span><span class=\"n\">message</span><span class=\"p\">)</span>\n<span class=\"kd\">struct</span> <span class=\"kt\">MessageEntity</span><span class=\"p\">:</span> <span class=\"kt\">IndexedEntity</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// The text content of the message</span>\n  <span class=\"kd\">@Property</span><span class=\"p\">(</span><span class=\"nv\">indexingKey</span><span class=\"p\">:</span> <span class=\"p\">\\</span><span class=\"o\">.</span><span class=\"n\">textContent</span><span class=\"p\">)</span>\n  <span class=\"k\">var</span> <span class=\"nv\">body</span><span class=\"p\">:</span> <span class=\"kt\">AttributedString</span><span class=\"p\">?</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>…where <code class=\"language-plaintext highlighter-rouge\">messages</code> is the overall schema, and the <code class=\"language-plaintext highlighter-rouge\">message</code> is the domain within it. Xcode will also autocomplete the fields you need to implement a domain. Again, if your app’s data fits into a schema, it’s 100% what you should use. What’s less clear to me is what you can do, or should do, and how far your app can participate with Siri AI if you don’t fit into one of these predefined boxes.</p>\n\n<h3 id=\"on-screen-awareness\">On-screen Awareness</h3>\n<p>Once you’ve indexed data and exposed it to the system, next you wanna take part in that whole “Yo Siri, tell me about X or Y”, where X or Y is something currently on screen. Two different routes here:</p>\n\n<ol>\n  <li>\n    <p><code class=\"language-plaintext highlighter-rouge\">NSUserActivity</code>: The tried and true API around, since what — iOS 8?, can help with singular content. For example, a photo.</p>\n  </li>\n  <li>\n    <p>View annotations API: Use this when you’ve got more than one singular thing that’s presented, like a list of stuff.</p>\n  </li>\n</ol>\n\n<p>Together, these tie back to an <code class=\"language-plaintext highlighter-rouge\">AppEntity</code>, which means everything is structured in a way Siri can understand. Here’s how they look:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">struct</span> <span class=\"kt\">MyPractice</span><span class=\"p\">:</span> <span class=\"kt\">View</span> <span class=\"p\">{</span>\n    <span class=\"k\">let</span> <span class=\"nv\">practice</span><span class=\"p\">:</span> <span class=\"kt\">Practice</span>\n\n    <span class=\"k\">var</span> <span class=\"nv\">body</span><span class=\"p\">:</span> <span class=\"kd\">some</span> <span class=\"kt\">View</span> <span class=\"p\">{</span>\n        <span class=\"kt\">VStack</span> <span class=\"p\">{</span>\n            <span class=\"kt\">StuffAndThings</span><span class=\"p\">()</span>\n            <span class=\"kt\">PracticeContainer</span><span class=\"p\">()</span>\n            <span class=\"o\">.</span><span class=\"nf\">userActivity</span><span class=\"p\">(</span><span class=\"s\">\"com.example.elitehoops.practice\"</span><span class=\"p\">,</span> \n                          <span class=\"nv\">element</span><span class=\"p\">:</span> <span class=\"n\">practice</span><span class=\"o\">.</span><span class=\"nf\">asEntity</span><span class=\"p\">())</span> <span class=\"p\">{</span> <span class=\"n\">entity</span><span class=\"p\">,</span> <span class=\"n\">activity</span> <span class=\"k\">in</span>\n              <span class=\"n\">activity</span><span class=\"o\">.</span><span class=\"n\">title</span> <span class=\"o\">=</span>  <span class=\"n\">practice</span><span class=\"o\">.</span><span class=\"n\">title</span>\n              <span class=\"n\">activity</span><span class=\"o\">.</span><span class=\"n\">appEntityIdentifier</span> <span class=\"o\">=</span> <span class=\"o\">.</span><span class=\"nf\">init</span><span class=\"p\">(</span><span class=\"nv\">for</span><span class=\"p\">:</span> <span class=\"n\">entity</span><span class=\"p\">)</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>And for view annotations:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">struct</span> <span class=\"kt\">MyPractices</span><span class=\"p\">:</span> <span class=\"kt\">View</span> <span class=\"p\">{</span>\n    <span class=\"k\">let</span> <span class=\"nv\">practices</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"kt\">Practice</span><span class=\"p\">]</span>\n\n    <span class=\"k\">var</span> <span class=\"nv\">body</span><span class=\"p\">:</span> <span class=\"kd\">some</span> <span class=\"kt\">View</span> <span class=\"p\">{</span>\n        <span class=\"kt\">ForEach</span><span class=\"p\">(</span><span class=\"n\">practices</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">p</span> <span class=\"k\">in</span> \n            <span class=\"kt\">PracticeView</span><span class=\"p\">(</span><span class=\"nv\">practice</span><span class=\"p\">:</span> <span class=\"n\">p</span><span class=\"p\">)</span>\n                <span class=\"o\">.</span><span class=\"nf\">appEntityIdentifier</span><span class=\"p\">(</span>\n                      <span class=\"kt\">EntityIdentifier</span><span class=\"p\">(</span>\n                          <span class=\"nv\">for</span><span class=\"p\">:</span> <span class=\"kt\">PracticeEntity</span><span class=\"o\">.</span><span class=\"k\">self</span><span class=\"p\">,</span>\n                          <span class=\"nv\">identifier</span><span class=\"p\">:</span> <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">id</span>\n                      <span class=\"p\">)</span>\n                <span class=\"p\">)</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"handle-data-coming-in-and-out\">Handle Data Coming In and Out</h3>\n<p>Finally, getting data out and in. When Siri wants to chain together stuff, like “Hey Siri, email this practice to Jansyn.” — we’ve now got a few moving parts. There’s the “practice”, I need to export my own data, and then there’s the recipient, Mail. To export or import, look no further than <code class=\"language-plaintext highlighter-rouge\">Transferable</code>.</p>\n\n<p>There is some nuance depending on the context. If you’re trying to handle an incoming request against some existing content, then you’ll need <code class=\"language-plaintext highlighter-rouge\">IntentValueQuery</code>. But, if that request means your app should creating a new model or data, then implement the <code class=\"language-plaintext highlighter-rouge\">importing</code> bit when wiring up your <code class=\"language-plaintext highlighter-rouge\">transferRepresentation</code> within <code class=\"language-plaintext highlighter-rouge\">Transferable</code>.</p>\n\n<p>In <a href=\"https://developer.apple.com/videos/play/wwdc2026/240?time=1159\">Apple’s session</a>, they use this example:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">struct</span> <span class=\"kt\">ContactEntityQuery</span><span class=\"p\">:</span> <span class=\"kt\">IntentValueQuery</span> <span class=\"p\">{</span>\n    <span class=\"kd\">func</span> <span class=\"nf\">values</span><span class=\"p\">(</span><span class=\"k\">for</span> <span class=\"nv\">input</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"kt\">IntentPerson</span><span class=\"p\">])</span> <span class=\"k\">async</span> <span class=\"k\">throws</span> <span class=\"o\">-&gt;</span> <span class=\"p\">[</span><span class=\"kt\">ContactEntity</span><span class=\"p\">]</span> <span class=\"p\">{</span>\n      <span class=\"k\">let</span> <span class=\"nv\">names</span> <span class=\"o\">=</span> <span class=\"n\">input</span><span class=\"o\">.</span><span class=\"nf\">map</span><span class=\"p\">(\\</span><span class=\"o\">.</span><span class=\"n\">displayName</span><span class=\"p\">)</span>\n      <span class=\"k\">let</span> <span class=\"nv\">descriptor</span> <span class=\"o\">=</span> <span class=\"kt\">FetchDescriptor</span><span class=\"o\">&lt;</span><span class=\"kt\">Contact</span><span class=\"o\">&gt;</span><span class=\"p\">()</span>\n      <span class=\"k\">let</span> <span class=\"nv\">contacts</span> <span class=\"o\">=</span> <span class=\"k\">try</span> <span class=\"n\">model</span><span class=\"o\">.</span><span class=\"n\">mainContext</span><span class=\"o\">.</span><span class=\"nf\">fetch</span><span class=\"p\">(</span><span class=\"n\">descriptor</span><span class=\"p\">)</span>\n      <span class=\"k\">let</span> <span class=\"nv\">matches</span> <span class=\"o\">=</span> <span class=\"n\">contacts</span><span class=\"o\">.</span><span class=\"n\">filter</span> <span class=\"p\">{</span> <span class=\"n\">contact</span> <span class=\"k\">in</span>\n          <span class=\"n\">names</span><span class=\"o\">.</span><span class=\"nf\">contains</span><span class=\"p\">(</span><span class=\"nv\">where</span><span class=\"p\">:</span> <span class=\"p\">{</span> <span class=\"n\">name</span> <span class=\"k\">in</span>\n              <span class=\"n\">contact</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"o\">.</span><span class=\"nf\">localizedStandardContains</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n          <span class=\"p\">})</span>\n      <span class=\"p\">}</span>\n      <span class=\"k\">return</span> <span class=\"n\">matches</span><span class=\"o\">.</span><span class=\"nf\">map</span><span class=\"p\">(\\</span><span class=\"o\">.</span><span class=\"n\">entity</span><span class=\"p\">)</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>However, this is the part that feels slightly limiting. It’s typed to handle only an <code class=\"language-plaintext highlighter-rouge\">IntentPerson</code> — something the system already defines. As far as I can tell, your app would <em>have</em> to use some value-known intent already, like <code class=\"language-plaintext highlighter-rouge\">IntentPerson</code> or something from the App Schemas. Otherwise, you also wouldn’t be able to use <code class=\"language-plaintext highlighter-rouge\">IntentValueRepresentation</code> — which is exactly what Siri uses for this type of stuff.</p>\n\n<p>Here’s another example I found <a href=\"https://developer.apple.com/documentation/appintents/intentvaluerepresentation\">in the docs</a>, which handles things bidirectionally:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">extension</span> <span class=\"kt\">TeamEntity</span><span class=\"p\">:</span> <span class=\"kt\">Transferable</span> <span class=\"p\">{</span>\n    <span class=\"kd\">static</span> <span class=\"k\">var</span> <span class=\"nv\">transferRepresentation</span><span class=\"p\">:</span> <span class=\"kd\">some</span> <span class=\"kt\">TransferRepresentation</span> <span class=\"p\">{</span>\n        <span class=\"kt\">IntentValueRepresentation</span><span class=\"p\">(</span>\n            <span class=\"nv\">exporting</span><span class=\"p\">:</span> <span class=\"p\">{</span> <span class=\"n\">entity</span> <span class=\"k\">in</span>\n                <span class=\"kt\">IntentPerson</span><span class=\"p\">(</span><span class=\"nv\">name</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"nf\">displayName</span><span class=\"p\">(</span><span class=\"n\">entity</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">))</span>\n            <span class=\"p\">},</span>\n            <span class=\"nv\">importing</span><span class=\"p\">:</span> <span class=\"p\">{</span> <span class=\"n\">person</span> <span class=\"k\">in</span>\n                <span class=\"kt\">ContactEntity</span><span class=\"p\">(</span><span class=\"nv\">name</span><span class=\"p\">:</span> <span class=\"n\">person</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"o\">.</span><span class=\"n\">displayString</span><span class=\"p\">)</span>\n            <span class=\"p\">}</span>\n        <span class=\"p\">)</span>\n        <span class=\"kt\">DataRepresentation</span><span class=\"p\">(</span><span class=\"nv\">exportedContentType</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"n\">utf8PlainText</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">entity</span> <span class=\"k\">in</span>\n            <span class=\"n\">entity</span><span class=\"o\">.</span><span class=\"nf\">teamSummaryText</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"nf\">data</span><span class=\"p\">(</span><span class=\"nv\">using</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"n\">utf8</span><span class=\"p\">)</span> <span class=\"p\">??</span> <span class=\"o\">.</span><span class=\"nf\">init</span><span class=\"p\">()</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<p>So, I’m unsure of how to handle this beyond that. If our apps don’t fit into schema, where does that leave us? I haven’t found the answer to that.</p>\n\n<h3 id=\"final-thoughts\">Final Thoughts</h3>\n<p>New Siri looks fantastic. No doubt, integrating it will finally bring us to that “This is what I wanted” phase of the tech. It should be an epochal event for our little digital assistant. For us? The APIs are easy to use, and there isn’t much guesswork. My only question mark is how to best integrate when our data models don’t fit into an App Schema, and if I find concrete answers — I’ll update this post.</p>\n\n<p>Until next time ✌️</p>",
            "summary": "The dawn of a new Siri (AI) looms in the air. When it ships, the promise of just saying what you want done, and having Siri just…do it, should be realistic. Apple, true to their roots of being masterful storytellers in terms of product, had many examples on tap. “Hey Siri, what was the water bottle I was thinking of getting a few months ago?”, and BAM — Siri went through a mountain of personal context, and found the answer.",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-06-15T00:00:00-05:00",
            "date_modified": "2026-06-15T00:00:00-05:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["Siri"]},{
            "id": "https://swiftjectivec.com/iOS-27-Notable-UIKit-Additions",
            "url": "https://swiftjectivec.com/iOS-27-Notable-UIKit-Additions/",
            "title": "iOS 27: Notable UIKit Additions",
            "content_html": "<p>Times…they <code class=\"language-plaintext highlighter-rouge\">are.concact(.haveBeen)</code> changing. In years past, I’d wait for the “What’s New in UIKit” video to hit towards the end of dub dub week, pour through the new docs to see what was added, and then fumble my way around Xcode to get the first examples of the changes up and running.</p>\n\n<p>And now? Well, I just…kinda, did this:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/UIKit2026_1.jpg\" role=\"presentation\" srcset=\"../assets/images/UIKit2026_1.jpg\" alt=\"Xcode Agentic Prompting for UIKit iOS 27 Changes.\" /></p>\n\n<p>Within minutes, I now had workable code samples of all the changes, explanations of what they were, and docs. I prayed for days like this, man.</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/UIKit2026_3.jpg\" role=\"presentation\" srcset=\"../assets/images/UIKit2026_3.jpg\" alt=\"Code catalog of UIKit changes in iOS27.\" /></p>\n\n<p><em>It used to take so much more work!</em></p>\n\n<p>There’s even a skill for this sort of thing, I have to imagine Cupertino &amp; Friends™️ made it just to throw me a bone for my annual UIKit post:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/UIKit2026_2.jpg\" role=\"presentation\" srcset=\"../assets/images/UIKit2026_2.jpg\" alt=\"Xcode Skill for UIKit.\" /></p>\n\n<p>As of today, the pathway to utilizing UIKit is virtually nothing. I’d argue now is a better time than ever (yes — really!) to give our trusty ol’ UI framework a go in your app. Apple has given access to <a href=\"https://x.com/luka_bernardi/status/2064125324485390383\">skills</a> to do it correctly, efficiently, and quickly. So, let’s see what’s new.</p>\n\n<p>If you want to catch up on this series first, you can view the <a href=\"https://swiftjectivec.com/iOS-11-notable-uikit-additions\">iOS 11</a>, <a href=\"https://swiftjectivec.com/iOS-12-notable-uikit-additions\">iOS 12</a>, <a href=\"https://swiftjectivec.com/iOS-13-notable-uikit-additions\">iOS 13</a>, <a href=\"https://swiftjectivec.com/iOS-14-notable-uikit-additions\">iOS 14</a>, <a href=\"https://swiftjectivec.com/iOS-15-notable-uikit-additions\">iOS 15</a>, <a href=\"https://swiftjectivec.com/iOS-16-notable-uikit-additions\">iOS 16</a>, <a href=\"https://swiftjectivec.com/iOS-17-notable-uikit-additions\">iOS 17</a>, <a href=\"https://swiftjectivec.com/iOS-18-notable-uikit-additions\">iOS 18</a>, and <a href=\"https://swiftjectivec.com/iOS-26-notable-uikit-additions\">iOS 26</a> versions of this article.</p>\n\n<section class=\"bg-indigo-50 border-l-8 border-indigo-500 text-gray-800 rounded-md my-10 dark:text-gray-300 dark:bg-gray-600 dark:border-indigo-700 \">\n    <div class=\"px-5 font-mono\">\n        <p class=\"pt-2 md:pt-4\"><span class=\"text-purple-600 dark:text-purple-400\">let</span> concatenatedThoughts = <span class=\"text-red-600\">\"\"\"</span></p>\n        <p class=\"text-gray-600 dark:text-gray-300 text-sm md:text-base\">Looking for the header diffs? Kyle Howells posted them <a href=\"https://gist.github.com/kylehowells/32c7f7475698b5f74eeb183f8db9d186\">here</a>.</p>\n        <p class=\"pb-2 md:pb-4 text-gray-600 text-base\"><span class=\"text-red-600\">\"\"\"</span></p>\n    </div>\n</section>\n\n<h2 id=\"navigation-bar--bar-buttons\">Navigation Bar &amp; Bar Buttons</h2>\n\n<p>The nav bar and its friends got quite a bit of attention, and to be honest that’s where we will find most of the changes. They adapt to all sorts of sizes and situations…hmmm, <a href=\"https://x.com/samhenrigold/status/2064069948486320528/photo/1\">I WONDER WHY</a>!?</p>\n\n<h3 id=\"navigation-bar-minimization\">Navigation Bar Minimization</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uinavigationitem/barminimizebehavior\">Docs</a></p>\n\n<p>Each view controller now gets a say in whether its navigation bar shrinks down as you scroll. It’s a great fit for content-heavy screens where every vertical point counts, while your settings or tool-laden screens can keep the bar pinned right where it is. There’s a companion safe-area API too, which decides whether your content slides up into the space that minimized bar leaves behind.</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">navigationItem</span><span class=\"o\">.</span><span class=\"n\">barMinimizeBehavior</span> <span class=\"o\">=</span> <span class=\"o\">.</span><span class=\"n\">onScrollDown</span>\n<span class=\"n\">navigationItem</span><span class=\"o\">.</span><span class=\"n\">barMinimizationSafeAreaAdjustment</span> <span class=\"o\">=</span> <span class=\"o\">.</span><span class=\"n\">enabled</span>\n</code></pre></div></div>\n\n<h3 id=\"bar-button-visibility-priority\">Bar Button Visibility Priority</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uibarbuttonitem/visibilitypriority\">Docs</a></p>\n\n<p>You can now rank your bar button items, so UIKit knows which actions to hang onto longest when space gets tight. Think iPad, Stage Manager, toolbars, resizable windows, FOLDABLES, — anywhere the available bar width is a moving target. The important stuff you tagged sticks around, and the rest dips out.</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">saveItem</span><span class=\"o\">.</span><span class=\"n\">visibilityPriority</span> <span class=\"o\">=</span> <span class=\"o\">.</span><span class=\"n\">high</span>\n<span class=\"n\">shareItem</span><span class=\"o\">.</span><span class=\"n\">visibilityPriority</span> <span class=\"o\">=</span> <span class=\"o\">.</span><span class=\"n\">standard</span>\n<span class=\"n\">printItem</span><span class=\"o\">.</span><span class=\"n\">visibilityPriority</span> <span class=\"o\">=</span> <span class=\"kt\">UIBarButtonItemVisibilityPriority</span><span class=\"p\">(</span><span class=\"nv\">lowerThan</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"n\">standard</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"removed-bar-button-padding\">Removed Bar Button Padding</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uibarbuttonitem/ispaddingremoved\">Docs</a></p>\n\n<p>Does exactly what it says on the tin — strips the default outer padding off a <code class=\"language-plaintext highlighter-rouge\">UIBarButtonItem</code>. I guess this one would be handy when your custom bar button view already brings its own inherent spacing, or you just need things to line up a bit tighter. Just keep an eye on your touch targets, the golden 44 point rule applies:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">let</span> <span class=\"nv\">colorItem</span> <span class=\"o\">=</span> <span class=\"kt\">UIBarButtonItem</span><span class=\"p\">(</span><span class=\"nv\">customView</span><span class=\"p\">:</span> <span class=\"n\">colorSwatch</span><span class=\"p\">)</span>\n<span class=\"n\">colorItem</span><span class=\"o\">.</span><span class=\"n\">isPaddingRemoved</span> <span class=\"o\">=</span> <span class=\"kc\">true</span>\n</code></pre></div></div>\n\n<h2 id=\"scenes-windows--orientation\">Scenes, Windows &amp; Orientation</h2>\n\n<p>Apple keeps marching toward a multi-window, resizable, scene-everywhere world, and…yeah, forget it. Because of the foldable that’s coming, that’s why. To wit, <a href=\"https://developer.apple.com/documentation/xcode/device-hub\">device hub</a> makes all of this quick to test out.</p>\n\n<h3 id=\"scene-closure-confirmation\">Scene Closure Confirmation</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/UIKit/UISceneClosureConfirmation\">Docs</a></p>\n\n<p>Ever close a window and immediately wish you hadn’t? This lets your app throw up a system confirmation before a scene actually closes, mimicking how several web apps work today. It’s made for multi-window document, editing, or workflow-ish type apps — basically anywhere slamming a window shut could toss out unsaved work or cut off something mid-flight.</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">windowScene</span><span class=\"o\">.</span><span class=\"n\">closureConfirmation</span> <span class=\"o\">=</span> <span class=\"kt\">UISceneClosureConfirmation</span><span class=\"p\">(</span>\n    <span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"Unsaved Changes\"</span><span class=\"p\">,</span>\n    <span class=\"nv\">message</span><span class=\"p\">:</span> <span class=\"s\">\"Save before closing this window?\"</span><span class=\"p\">,</span>\n    <span class=\"nv\">actions</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n        <span class=\"kt\">UIAlertAction</span><span class=\"p\">(</span><span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"Save and Close\"</span><span class=\"p\">,</span> <span class=\"nv\">style</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"k\">default</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">_</span> <span class=\"k\">in</span> <span class=\"nf\">saveDocument</span><span class=\"p\">()</span> <span class=\"p\">},</span>\n        <span class=\"kt\">UIAlertAction</span><span class=\"p\">(</span><span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"Discard Changes\"</span><span class=\"p\">,</span> <span class=\"nv\">style</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"n\">destructive</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">_</span> <span class=\"k\">in</span> <span class=\"nf\">discardChanges</span><span class=\"p\">()</span> <span class=\"p\">}</span>\n    <span class=\"p\">]</span>\n<span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"external-display-scene-accessories\">External Display Scene Accessories</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uiviewcontroller/registersceneaccessory(_:)\">Docs</a></p>\n\n<p>A view controller can now register a secondary, noninteractive scene built for an external display. Looking at the docs, I think this would be cool for auxiallary presentation screens, dashboards, reference views, or any companion output you’d want to toss up on a connected display where touch input isn’t always required:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">let</span> <span class=\"nv\">configuration</span> <span class=\"o\">=</span> <span class=\"kt\">UISceneConfiguration</span><span class=\"p\">(</span><span class=\"nv\">name</span><span class=\"p\">:</span> <span class=\"s\">\"Presenter Display\"</span><span class=\"p\">)</span>\n<span class=\"k\">let</span> <span class=\"nv\">accessory</span> <span class=\"o\">=</span> <span class=\"kt\">UISceneAccessory</span><span class=\"o\">.</span><span class=\"nf\">externalNonInteractive</span><span class=\"p\">(</span><span class=\"nv\">sceneConfiguration</span><span class=\"p\">:</span> <span class=\"n\">configuration</span><span class=\"p\">)</span>\n\n<span class=\"k\">let</span> <span class=\"nv\">registration</span> <span class=\"o\">=</span> <span class=\"nf\">registerSceneAccessory</span><span class=\"p\">(</span><span class=\"n\">accessory</span><span class=\"p\">)</span>\n<span class=\"n\">registration</span><span class=\"o\">.</span><span class=\"n\">isEnabled</span> <span class=\"o\">=</span> <span class=\"n\">registration</span><span class=\"o\">.</span><span class=\"n\">isAvailable</span>\n</code></pre></div></div>\n\n<h3 id=\"per-scene-supported-orientations\">Per-Scene Supported Orientations</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/UIKit/UIWindowSceneDelegate/supportedInterfaceOrientations(for:)\">Docs</a></p>\n\n<p>Each window scene can now declare its <em>own</em> supported orientations. So in a multi-window app, your video scene can stay locked to landscape while the browsing or editing scene happily rotates whichever way it likes. This flexibility is great, as I’ve had several times where one-size-fits-all orientation rules didn’t quite apply for the whole app:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">func</span> <span class=\"nf\">supportedInterfaceOrientations</span><span class=\"p\">(</span>\n    <span class=\"k\">for</span> <span class=\"nv\">windowScene</span><span class=\"p\">:</span> <span class=\"kt\">UIWindowScene</span>\n<span class=\"p\">)</span> <span class=\"o\">-&gt;</span> <span class=\"kt\">UIInterfaceOrientationMask</span> <span class=\"p\">{</span>\n    <span class=\"o\">.</span><span class=\"n\">landscape</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"tab-bars--sidebars\">Tab Bars &amp; Sidebars</h2>\n\n<p>The tab bar and sidebar duo (the latter of which ditched the design from iOS 26 i loved 😢) picked up some welcome controls for steering which one shows up, and what gets the spotlight.</p>\n\n<h3 id=\"prominent-tab-selection\">Prominent Tab Selection</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uitabbarcontroller/prominenttabidentifier\">Docs</a></p>\n\n<p>Got one tab that matters more than the others? A <code class=\"language-plaintext highlighter-rouge\">UITabBarController</code> can now crown a single tab as visually prominent — perfect for a headline action like compose, search, cart, create, or record:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"n\">prominentTabIdentifier</span> <span class=\"o\">=</span> <span class=\"s\">\"compose\"</span>\n<span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"nf\">setProminentTabIdentifier</span><span class=\"p\">(</span><span class=\"s\">\"inbox\"</span><span class=\"p\">,</span> <span class=\"nv\">animated</span><span class=\"p\">:</span> <span class=\"kc\">true</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h3 id=\"sidebar-preferred-placement\">Sidebar Preferred Placement</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/UIKit/UITabBarController/Sidebar-swift.class/preferredPlacement\">Docs</a></p>\n\n<p>When only one can win, this lets a tab bar controller say whether it’d rather show up as a sidebar or a tab bar. It’s great for apps that are sidebar-first at heart, but still need to fold down gracefully to a tab bar on more compact devices or…whatever, you know at this point. I’d assume foldables:</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"n\">mode</span> <span class=\"o\">=</span> <span class=\"o\">.</span><span class=\"n\">tabSidebar</span>\n<span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"n\">sidebar</span><span class=\"o\">.</span><span class=\"n\">preferredPlacement</span> <span class=\"o\">=</span> <span class=\"o\">.</span><span class=\"n\">sidebar</span>\n</code></pre></div></div>\n\n<h3 id=\"batching-tab-bar-updates\">Batching Tab Bar Updates</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uitabbarcontroller/performbatchupdates(_:)\">Docs</a></p>\n\n<p>Changing a whole bunch of tab stuff at once — badges, images, ordering, prominent state — and want to dodge the flicker? Batch it. UIKit folds all of those changes into a single update pass instead of grinding through a separate layout pass for each one.</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"n\">performBatchUpdates</span> <span class=\"p\">{</span>\n    <span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"n\">tabs</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">badgeValue</span> <span class=\"o\">=</span> <span class=\"s\">\"3\"</span>\n    <span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"n\">tabs</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">image</span> <span class=\"o\">=</span> <span class=\"kt\">UIImage</span><span class=\"p\">(</span><span class=\"nv\">systemName</span><span class=\"p\">:</span> <span class=\"s\">\"star.fill\"</span><span class=\"p\">)</span>\n    <span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"nf\">setProminentTabIdentifier</span><span class=\"p\">(</span><span class=\"s\">\"favorites\"</span><span class=\"p\">,</span> <span class=\"nv\">animated</span><span class=\"p\">:</span> <span class=\"kc\">false</span><span class=\"p\">)</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"sidebar-availability-tracking\">Sidebar Availability Tracking</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uitabbarcontroller/sidebar-swift.class/isavailable\">Docs</a></p>\n\n<p>A simple read on whether your tab/sidebar interface actually has a sidebar available at the moment. It’s handy for adjusting your supporting UI when that sidebar slides in or out thanks to a size class change, a rotation, or a window resize.</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"kd\">func</span> <span class=\"nf\">tabBarController</span><span class=\"p\">(</span>\n    <span class=\"n\">_</span> <span class=\"nv\">tabBarController</span><span class=\"p\">:</span> <span class=\"kt\">UITabBarController</span><span class=\"p\">,</span>\n    <span class=\"n\">sidebarAvailabilityDidChange</span> <span class=\"nv\">sidebar</span><span class=\"p\">:</span> <span class=\"kt\">UITabBarController</span><span class=\"o\">.</span><span class=\"kt\">Sidebar</span>\n<span class=\"p\">)</span> <span class=\"p\">{</span>\n    <span class=\"n\">tabBarController</span><span class=\"o\">.</span><span class=\"n\">navigationItem</span><span class=\"o\">.</span><span class=\"n\">leftBarButtonItem</span> <span class=\"o\">=</span> <span class=\"n\">sidebar</span><span class=\"o\">.</span><span class=\"n\">isAvailable</span> <span class=\"p\">?</span> <span class=\"nv\">nil</span> <span class=\"p\">:</span> <span class=\"n\">menuButton</span>\n<span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h2 id=\"bonus-points\">Bonus Points</h2>\n\n<p>And, as always, then there’s the usual grab bag. Here are a few odds and ends that didn’t fit tidly into the stuff above, but are worth a look all the same.</p>\n\n<h3 id=\"menu-image-visibility\">Menu Image Visibility</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uimenuelement/preferredimagevisibility\">Docs</a></p>\n\n<p>Menu elements can now explicitly ask for their images to be shown, hidden, or simply left up to the system. Lean on it when the icon <em>is</em> the information — color swatches, say — or hide them away when icons would only add noise to an otherwise text-heavy menu.</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">let</span> <span class=\"nv\">red</span> <span class=\"o\">=</span> <span class=\"kt\">UIAction</span><span class=\"p\">(</span>\n    <span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"Red\"</span><span class=\"p\">,</span>\n    <span class=\"nv\">image</span><span class=\"p\">:</span> <span class=\"kt\">UIImage</span><span class=\"p\">(</span><span class=\"nv\">systemName</span><span class=\"p\">:</span> <span class=\"s\">\"circle.fill\"</span><span class=\"p\">),</span>\n    <span class=\"nv\">preferredImageVisibility</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"n\">visible</span>\n<span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">_</span> <span class=\"k\">in</span> <span class=\"nf\">applyColor</span><span class=\"p\">(</span><span class=\"o\">.</span><span class=\"n\">systemRed</span><span class=\"p\">)</span> <span class=\"p\">}</span>\n\n<span class=\"k\">let</span> <span class=\"nv\">reset</span> <span class=\"o\">=</span> <span class=\"kt\">UIAction</span><span class=\"p\">(</span>\n    <span class=\"nv\">title</span><span class=\"p\">:</span> <span class=\"s\">\"Reset Formatting\"</span><span class=\"p\">,</span>\n    <span class=\"nv\">image</span><span class=\"p\">:</span> <span class=\"kt\">UIImage</span><span class=\"p\">(</span><span class=\"nv\">systemName</span><span class=\"p\">:</span> <span class=\"s\">\"textformat\"</span><span class=\"p\">),</span>\n    <span class=\"nv\">preferredImageVisibility</span><span class=\"p\">:</span> <span class=\"o\">.</span><span class=\"n\">hidden</span>\n<span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">_</span> <span class=\"k\">in</span> <span class=\"nf\">resetFormatting</span><span class=\"p\">()</span> <span class=\"p\">}</span>\n</code></pre></div></div>\n\n<h3 id=\"document-launch-screen-subtitle\">Document Launch Screen Subtitle</h3>\n\n<p><a href=\"https://developer.apple.com/documentation/uikit/uidocumentviewcontroller/launchoptions-swift.class/subtitle\">Docs</a></p>\n\n<p>I mean…why not? Subtitles!</p>\n\n<div class=\"language-swift highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"k\">let</span> <span class=\"nv\">launchOptions</span> <span class=\"o\">=</span> <span class=\"kt\">UIDocumentViewController</span><span class=\"o\">.</span><span class=\"kt\">LaunchOptions</span><span class=\"p\">()</span>\n<span class=\"n\">launchOptions</span><span class=\"o\">.</span><span class=\"n\">subtitle</span> <span class=\"o\">=</span> <span class=\"s\">\"Create and edit presentations\"</span>\n\n<span class=\"k\">let</span> <span class=\"nv\">documentViewController</span> <span class=\"o\">=</span> <span class=\"kt\">UIDocumentViewController</span><span class=\"p\">(</span><span class=\"nv\">launchOptions</span><span class=\"p\">:</span> <span class=\"n\">launchOptions</span><span class=\"p\">)</span>\n</code></pre></div></div>\n\n<h2 id=\"final-thoughts\">Final Thoughts</h2>\n\n<p>A few years ago, I wondered if UIKit would be deprecated altogether. That would’ve been drastic, sure, but I <em>did</em> wonder. These days, I don’t share the same concern anymore. SwiftUI gets better each year, and yeah — it’ll have top billing. But UIKit is solid, and it appears to be a core part of Apple’s strategy into the future.</p>\n\n<p>Not much changed this year, and not much was added that’s flashy. But, that’s true of iOS 27 in several ways. This year, it’s about getting Siri right, and I think that’s the right move.</p>\n\n<p>Until next time ✌️</p>",
            "summary": "Times…they are.concact(.haveBeen) changing. In years past, I’d wait for the “What’s New in UIKit” video to hit towards the end of dub dub week, pour through the new docs to see what was added, and then fumble my way around Xcode to get the first examples of the changes up and running.",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-06-08T00:00:00-05:00",
            "date_modified": "2026-06-08T00:00:00-05:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["UIKit"]},{
            "id": "https://swiftjectivec.com/WWDC-2026-The-Pregame-Quiz",
            "url": "https://swiftjectivec.com/WWDC-2026-The-Pregame-Quiz/",
            "title": "W.W.D.C. 2026: The Pregame Quiz",
            "content_html": "<p>Tern up for what! They’ll never Ternus against each other! Okay. <em>Sorry</em>. I’m done now. But it is that time…</p>\n\n<p><span class=\"relative inline-block not-prose pb-2 md:pb-[0.25px]\"><span class=\"bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-purple-500 font-semibold\">The 12th annual Swiftjective-C pregame quiz is here!</span><span class=\"absolute left-0 bottom-0 w-full h-1.5\" style=\"background-image: url(&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 6' preserveAspectRatio='none'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0%25' y1='0%25' x2='100%25' y2='0%25'%3E%3Cstop offset='0%25' stop-color='%233b82f6'/%3E%3Cstop offset='100%25' stop-color='%238b5cf6'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M0,6 Q50,0 100,6' fill='none' stroke='url(%23g)' stroke-width='1.75'/%3E%3C/svg%3E&quot;); background-size: 100% 100%; background-repeat: no-repeat;\"></span></span></p>\n\n<p>This year, I’m rolling with (mostly) 2026 news, updates, and shenanigans. No “Objective-C without the C” questions, or Steve Notes, or other Swiftjective-C staples of year’s past. This edition is all about stuff Cupertino &amp; Friends™️ have shipped, announced, clarified, regulated, re-org’d or otherwise made us all read release notes about this year.</p>\n\n<p>If you want to warm up first, you’ve got eleven years of quiz backlog to spelunk through:</p>\n\n<div class=\"not-prose grid grid-cols-2 md:grid-cols-3 gap-x-6 gap-y-6 my-12\">\n  <!-- WWDC 2015 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2015-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2015.png\" alt=\"WWDC 2015\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2015</div>\n  </a>\n  <!-- WWDC 2016 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2016-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2016.png\" alt=\"WWDC 2016\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2016</div>\n  </a>\n  <!-- WWDC 2017 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2017-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2017.png\" alt=\"WWDC 2017\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2017</div>\n  </a>\n  <!-- WWDC 2018 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2018-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2018.png\" alt=\"WWDC 2018\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2018</div>\n  </a>\n  <!-- WWDC 2019 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2019-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2019.png\" alt=\"WWDC 2019\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2019</div>\n  </a>\n  <!-- WWDC 2020 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2020-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2020.png\" alt=\"WWDC 2020\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2020</div>\n  </a>\n  <!-- WWDC 2021 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2021-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2021.png\" alt=\"WWDC 2021\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2021</div>\n  </a>\n  <!-- WWDC 2022 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2022-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2022.png\" alt=\"WWDC 2022\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2022</div>\n  </a>\n  <!-- WWDC 2023 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2023-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2023.png\" alt=\"WWDC 2023\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2023</div>\n  </a>\n  <!-- WWDC 2024 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2024-The-Pregame-Quiz-copy\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/dd2024.png\" alt=\"WWDC 2024\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2024</div>\n  </a>\n  \n  <!-- WWDC 2025 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2025-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/wwdc2025.jpg\" alt=\"WWDC 2025\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2025</div>\n  </a>\n  \n  \n  <!-- WWDC 2026 -->\n  <a href=\"https://swiftjectivec.com/WWDC-2026-The-Pregame-Quiz\" class=\"flex flex-col items-center w-full max-w-xs md:max-w-none mx-auto\">\n    <div class=\"w-full aspect-[2.2/1] md:aspect-[2.86/1] overflow-hidden rounded-md shadow transition-transform hover:scale-105 flex items-center justify-center\">\n      <img src=\"../assets/images/wwdc2026.jpg\" alt=\"WWDC 2026\" class=\"object-cover h-full w-full\" loading=\"lazy\" width=\"160\" height=\"56\" />\n    </div>\n    <div class=\"text-center mt-2 text-xs font-semibold text-gray-600\">WWDC 2026</div>\n  </a>\n  \n</div>\n\n<h3 id=\"ground-rules\">Ground Rules</h3>\n\n<p>There are three rounds, and the point break down is as follows:</p>\n\n<ul>\n  <li><strong>Round 1</strong> - 1 point each answer</li>\n  <li><strong>Round 2</strong> - 2 points each answer</li>\n  <li><strong>Round 3</strong> - 3 points each answer</li>\n</ul>\n\n<p>The last question of each round is an optional wildcard question. Get it right, and your team gets <strong>4</strong> <strong>points</strong>, <em>but</em> miss it and the team will be <strong>deducted 2 points</strong>.</p>\n\n<div class=\"not-prose mt-8 -mb-4\">\n  <h3 class=\"bg-gradient-to-l from-blue-500 to-fuchsia-500 bg-clip-text text-transparent text-2xl font-bold leading-relaxed\">\n    Round 1 - App Store Paperwork Speedrun\n  </h3>\n</div>\n<p>Nothing says pre-W.W.D.C. vibes quite like reading support docs, release notes and regulatory compliance copy. With that, let’s emotionally process App Store Connect together.</p>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 1</legend>\n  <p class=\"quiz-prompt\">In 2026, Apple detailed changes to iOS in Japan that created new options for developers, including alternative marketplaces and payment options. Which law are those changes designed to comply with?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q1\" value=\"A\" /><span><strong>A:</strong> Digital Markets Act</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q1\" value=\"B\" /><span><strong>B:</strong> Mobile Software Competition Act</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q1\" value=\"C\" /><span><strong>C:</strong> App Store Modernization Act</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q1\" value=\"D\" /><span><strong>D:</strong> Platform Fairness Act</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 2</legend>\n  <p class=\"quiz-prompt\">The App Review Guidelines got a February 2026 clarification that apps with random or anonymous chat are subject to which guideline?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q2\" value=\"A\" /><span><strong>A:</strong> 2.5 Software Requirements</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q2\" value=\"B\" /><span><strong>B:</strong> 1.2 User-Generated Content</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q2\" value=\"C\" /><span><strong>C:</strong> 3.1.1 In-App Purchase</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q2\" value=\"D\" /><span><strong>D:</strong> 5.1.1 Data Collection and Storage</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 3</legend>\n  <p class=\"quiz-prompt\">Before February 17, 2026, an App Store bundle had a very hall-monitor rule: every included app had to support the same platform as the primary app. For new bundles, what did Apple stop requiring?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q3\" value=\"A\" /><span><strong>A:</strong> A bundle can include TestFlight-only beta builds</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q3\" value=\"B\" /><span><strong>B:</strong> A bundle can mix apps from multiple developer accounts</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q3\" value=\"C\" /><span><strong>C:</strong> A bundle can go live before every included app passes review</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q3\" value=\"D\" /><span><strong>D:</strong> Apps in a bundle no longer need to support the same platform as the primary app</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 4</legend>\n  <p class=\"quiz-prompt\">Apple's new monthly subscription with a 12-month commitment is basically an annual plan masquerading as a monthly sub. But, to me, that's not the oddest bit, it's the availability. Developers can offer it almost everywhere, but not in two storefronts. Which two are left out?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q4\" value=\"A\" /><span><strong>A:</strong> The United States and Singapore</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q4\" value=\"B\" /><span><strong>B:</strong> Japan and South Korea</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q4\" value=\"C\" /><span><strong>C:</strong> The European Union and United Kingdom</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q4\" value=\"D\" /><span><strong>D:</strong> Canada and Australia</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Wildcard</legend>\n  <p class=\"quiz-prompt\">In March 2026, Apple quietly retired a tiny App Store Connect lever that developers used when they wanted to hand out a free in-app thing without creating a whole campaign around it. What went away?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q5\" value=\"A\" /><span><strong>A:</strong> Introductory offers</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q5\" value=\"B\" /><span><strong>B:</strong> Win-back offers</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q5\" value=\"C\" /><span><strong>C:</strong> Promo codes for In-App Purchases</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q5\" value=\"D\" /><span><strong>D:</strong> Offer codes for subscriptions</span></label>\n    <label class=\"quiz-option quiz-option-skip\"><input type=\"radio\" name=\"q5\" value=\"skip\" /><span><strong>Skip:</strong> <span class=\"quiz-skip-copy\">I am a coward.</span></span></label>\n  </div>\n</fieldset>\n\n<div class=\"not-prose mt-8 -mb-4\">\n  <h3 class=\"bg-gradient-to-l from-blue-500 to-fuchsia-500 bg-clip-text text-transparent text-2xl font-bold leading-relaxed\">\n    Round 2 - Hardware and Tooling Side Quests\n  </h3>\n</div>\n<p>This year’s spring product and tooling cycle was inspired by…The Matrix? Let’s see who read the footnotes!</p>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 1</legend>\n  <p class=\"quiz-prompt\">iPhone 17e starts at the same $599 price as its predecessor, but Apple doubled the entry storage. What storage capacity does it start with?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q6\" value=\"A\" /><span><strong>A:</strong> 64GB</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q6\" value=\"B\" /><span><strong>B:</strong> 128GB</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q6\" value=\"C\" /><span><strong>C:</strong> 256GB</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q6\" value=\"D\" /><span><strong>D:</strong> 512GB</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 2</legend>\n  <p class=\"quiz-prompt\">Apple's March 2026 retail update says the new fanless MacBook Neo starts at $599 and, somehow, runs on an iPhone chip. Which chip powers it?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q7\" value=\"A\" /><span><strong>A:</strong> M4</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q7\" value=\"B\" /><span><strong>B:</strong> M5</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q7\" value=\"C\" /><span><strong>C:</strong> A18 Pro</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q7\" value=\"D\" /><span><strong>D:</strong> A19</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 3</legend>\n  <p class=\"quiz-prompt\">Hardware nerd alert question. The 2026 iPad Air with M4 brought two Apple-designed connectivity chips to the Air line. Which pair was it?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q8\" value=\"A\" /><span><strong>A:</strong> H2 and U2</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q8\" value=\"B\" /><span><strong>B:</strong> S10 and W4</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q8\" value=\"C\" /><span><strong>C:</strong> R1 and C1</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q8\" value=\"D\" /><span><strong>D:</strong> N1 and C1X</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 4</legend>\n  <p class=\"quiz-prompt\">MacBook Neo's color lineup looks like Apple put an iMac G3, some Starburst and a $599 price point in the same room. iPhone 5c vibes! Which of these is <i>not</i> one of the official colors?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q9\" value=\"A\" /><span><strong>A:</strong> Silver</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q9\" value=\"B\" /><span><strong>B:</strong> Blush</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q9\" value=\"C\" /><span><strong>C:</strong> Sage</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q9\" value=\"D\" /><span><strong>D:</strong> Indigo</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Wildcard</legend>\n  <p class=\"quiz-prompt\">Still on the Neo, Apple's marketing went fully TikTok fever dream for it: fruit, FaceTime and a laptop color called Citrus doing a lot of emotional work. And, I kinda dig it? In the clip that made r/apple take notice, which two fruits FaceTimed each other?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q10\" value=\"A\" /><span><strong>A:</strong> A lime and a lemon</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q10\" value=\"B\" /><span><strong>B:</strong> A banana and a blueberry</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q10\" value=\"C\" /><span><strong>C:</strong> An orange and a grapefruit</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q10\" value=\"D\" /><span><strong>D:</strong> A kiwi and a strawberry</span></label>\n    <label class=\"quiz-option quiz-option-skip\"><input type=\"radio\" name=\"q10\" value=\"skip\" /><span><strong>Skip:</strong> <span class=\"quiz-skip-copy\">I am a coward.</span></span></label>\n  </div>\n</fieldset>\n\n<div class=\"not-prose mt-8 -mb-4\">\n  <h3 class=\"bg-gradient-to-l from-blue-500 to-fuchsia-500 bg-clip-text text-transparent text-2xl font-bold leading-relaxed\">\n    Round 3 - Coming Bright Up\n  </h3>\n</div>\n<p>The conference page is glowing, Apple Park attendees are afoot, and Tim Cook has a new title on deck.</p>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 1</legend>\n  <p class=\"quiz-prompt\">As we all converge for dub dub, there is a central rally point in San Jose where the Apple developer diaspora seems to materialize before the week kicks off. Where are the hallowed grounds where everyone first meets on Saturday, and sometimes Sunday, before W.W.D.C.?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q11\" value=\"A\" /><span><strong>A:</strong> San Pedro Square Market</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q11\" value=\"B\" /><span><strong>B:</strong> Plaza de Cesar Chavez</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q11\" value=\"C\" /><span><strong>C:</strong> San Jose McEnery Convention Center</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q11\" value=\"D\" /><span><strong>D:</strong> SoFA Market</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 2</legend>\n  <p class=\"quiz-prompt\">The last fully in-person San Jose dub dub before everything became a browser tab was W.W.D.C. 2019. At the Thursday night Bash in Discovery Meadow, which band took the stage and turned a field of badge-wearing developers into the world's most type-safe alt-rock crowd?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q12\" value=\"A\" /><span><strong>A:</strong> Panic! At The Disco</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q12\" value=\"B\" /><span><strong>B:</strong> Weezer</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q12\" value=\"C\" /><span><strong>C:</strong> Fall Out Boy</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q12\" value=\"D\" /><span><strong>D:</strong> The Killers</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 3</legend>\n  <p class=\"quiz-prompt\">Before John Ternus was demoing titanium and starring in everyone's Apple succession takes, his Penn senior project already had very Apple-coded hardware-meets-human-need feel. What did he build?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q13\" value=\"A\" /><span><strong>A:</strong> A mechanical feeding arm controlled with head movements</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q13\" value=\"B\" /><span><strong>B:</strong> A prototype Cinema Display stand that folded flat enough for a backpack</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q13\" value=\"C\" /><span><strong>C:</strong> A haptic swim coach that buzzed when you drifted out of your lane</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q13\" value=\"D\" /><span><strong>D:</strong> A VR headset cooling rig made from PowerBook parts</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Question 4</legend>\n  <p class=\"quiz-prompt\">This year's pre-W.W.D.C. tea-leaf reading has not been subtle: glowing Swift birds, Siri rings and now Apple DNS archaeology. A few weeks before the keynote, which dormant Apple subdomain kicked off another round of \"oh, so it is AI season\" chatter?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q14\" value=\"A\" /><span><strong>A:</strong> brightup.apple.com</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q14\" value=\"B\" /><span><strong>B:</strong> siri.apple.com</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q14\" value=\"C\" /><span><strong>C:</strong> genai.apple.com</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q14\" value=\"D\" /><span><strong>D:</strong> ask.apple.com</span></label>\n  </div>\n</fieldset>\n\n<fieldset class=\"not-prose quiz-question\">\n  <legend class=\"quiz-kicker\">Wildcard</legend>\n  <p class=\"quiz-prompt\">The Apple Design Awards are basically Cupertino's annual \"yes, we noticed your pixels\" ceremony. This year's finalists span six categories, but one of these is not on the 2026 list. Which one is the beautiful impostor?</p>\n  <div class=\"quiz-options\">\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q15\" value=\"A\" /><span><strong>A:</strong> Inclusivity</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q15\" value=\"B\" /><span><strong>B:</strong> Interaction</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q15\" value=\"C\" /><span><strong>C:</strong> Spatial Computing</span></label>\n    <label class=\"quiz-option\"><input type=\"radio\" name=\"q15\" value=\"D\" /><span><strong>D:</strong> Visuals and Graphics</span></label>\n    <label class=\"quiz-option quiz-option-skip\"><input type=\"radio\" name=\"q15\" value=\"skip\" /><span><strong>Skip:</strong> <span class=\"quiz-skip-copy\">I am a coward.</span></span></label>\n  </div>\n</fieldset>\n\n<div class=\"flex gap-x-6 items-center\">\n<p>👉</p>\n<button class=\"rounded-md bg-indigo-50 px-4 py-2 text-sm font-semibold text-indigo-600 shadow-sm hover:bg-indigo-100\" onclick=\"calculateScore()\">Submit Quiz</button>\n<p>👈</p>\n</div>\n\n<script>\nvar quizShareText = \"\";\nvar quizShareUrl = \"https://swiftjectivec.com/WWDC-2026-The-Pregame-Quiz/\";\n\nfunction calculateScore() {\n    var correctAnswers = {\n        q1: \"B\",\n        q2: \"B\",\n        q3: \"D\",\n        q4: \"A\",\n        q5: \"C\",  // Wildcard question for Round 1\n        q6: \"C\",\n        q7: \"C\",\n        q8: \"D\",\n        q9: \"C\",\n        q10: \"A\", // Wildcard question for Round 2\n        q11: \"A\",\n        q12: \"B\",\n        q13: \"A\",\n        q14: \"C\",\n        q15: \"C\"  // Wildcard question for Round 3\n    };\n\n    var scoreSimple = 0;\n    var scoreDetailed = 0;\n    var incorrectAnswers = [];\n    var checkboxes = document.querySelectorAll('input[type=\"radio\"]');\n    function isWildcard(questionName) {\n        return questionName === \"q5\" || questionName === \"q10\" || questionName === \"q15\";\n    }\n\n    checkboxes.forEach(function(checkbox) {\n        var questionName = checkbox.name;\n        var isSkipped = checkbox.value === \"skip\";\n        if (checkbox.checked && checkbox.value === correctAnswers[questionName]) {\n            scoreSimple++;\n            if (isWildcard(questionName)) {\n                scoreDetailed += 4; // Wildcard question correct\n            } else if (questionName === \"q1\" || questionName === \"q2\" || questionName === \"q3\" || questionName === \"q4\") {\n                scoreDetailed += 1; // Round 1 questions\n            } else if (questionName === \"q6\" || questionName === \"q7\" || questionName === \"q8\" || questionName === \"q9\") {\n                scoreDetailed += 2; // Round 2 questions\n            } else if (questionName === \"q11\" || questionName === \"q12\" || questionName === \"q13\" || questionName === \"q14\") {\n                scoreDetailed += 3; // Round 3 questions\n            }\n        } else if (checkbox.checked && isWildcard(questionName) && !isSkipped && checkbox.value !== correctAnswers[questionName]) {\n            scoreDetailed -= 2; // Wildcard question incorrect\n        } \n\n        if (checkbox.checked && !isSkipped && checkbox.value !== correctAnswers[questionName]) {\n            var round, roundNumber, questionNumber;\n            var qNumber = parseInt(questionName.replace(\"q\", \"\"));\n            if (qNumber <= 5) {\n                round = \"Round One\";\n                roundNumber = 1;\n                questionNumber = qNumber;\n            } else if (qNumber <= 10) {\n                round = \"Round Two\";\n                roundNumber = 2;\n                questionNumber = qNumber - 5;\n            } else {\n                round = \"Round Three\";\n                roundNumber = 3;\n                questionNumber = qNumber - 10;\n            }\n            incorrectAnswers.push({\n                question: round + \": Question \" + questionNumber,\n                shortQuestion: \"R\" + roundNumber + \" Q\" + questionNumber,\n                correctAnswer: correctAnswers[questionName]\n            });\n        }\n    });\n\n    function selectedAnswer(questionName) {\n        var selected = document.querySelector('input[name=\"' + questionName + '\"]:checked');\n        return selected ? selected.value : null;\n    }\n\n    function buildRoundResult(roundName, questions) {\n        var correctCount = 0;\n        var marks = questions.map(function(questionName) {\n            var answer = selectedAnswer(questionName);\n            var isSkipped = answer === \"skip\";\n            var isCorrect = answer === correctAnswers[questionName];\n            if (isCorrect) {\n                correctCount++;\n            }\n\n            if (isSkipped) {\n                return \"➖\";\n            }\n\n            return isCorrect ? \"✅\" : \"🚫\";\n        });\n\n        return {\n            name: roundName,\n            marks: marks.join(\"\"),\n            correctCount: correctCount,\n            shareText: roundName + \": \" + marks.join(\"\") + \" (\" + correctCount + \"/5)\"\n        };\n    }\n\n    var roundResults = [\n        buildRoundResult(\"Round 1\", [\"q1\", \"q2\", \"q3\", \"q4\", \"q5\"]),\n        buildRoundResult(\"Round 2\", [\"q6\", \"q7\", \"q8\", \"q9\", \"q10\"]),\n        buildRoundResult(\"Round 3\", [\"q11\", \"q12\", \"q13\", \"q14\", \"q15\"])\n    ];\n\n    var shareText = [\n        \"Swiftjective-C W.W.D.C. 2026 Pregame Quiz\",\n        \"Score: \" + scoreDetailed + \"/36\",\n        \"\",\n        roundResults[0].shareText,\n        roundResults[1].shareText,\n        roundResults[2].shareText,\n        \"\",\n        \"Can you beat me before #WWDC26?\"\n    ].join(\"\\n\");\n    quizShareText = shareText;\n\n    document.getElementById('quizScoreValue').innerText = scoreDetailed;\n    document.getElementById('quizCorrectSummary').innerText = scoreSimple + \"/15\";\n    document.getElementById('quizMissedBadge').innerText = incorrectAnswers.length === 0 ? \"0\" : incorrectAnswers.length;\n    document.getElementById('quizRoundSummary').innerHTML = roundResults.map(function(result) {\n        return '<div class=\"grid grid-cols-[4.5rem_minmax(0,1fr)_auto] items-center gap-3 px-3 py-3 sm:grid-cols-[5rem_minmax(0,1fr)_auto]\">' +\n            '<div class=\"text-base/6 font-semibold text-zinc-900 dark:text-zinc-100 sm:text-sm/5\">' + result.name + '</div>' +\n            '<div class=\"min-w-0 text-lg leading-6 sm:text-base\">' + result.marks + '</div>' +\n            '<div class=\"text-base/6 font-semibold tabular-nums text-zinc-600 dark:text-zinc-300 sm:text-sm/5\">' + result.correctCount + '/5</div>' +\n            '</div>';\n    }).join(\"\");\n\n    if (incorrectAnswers.length > 0) {\n        document.getElementById('quizMissedDetails').classList.remove('hidden');\n        document.getElementById('quizMissedAnswers').innerHTML = incorrectAnswers.map(function(item) {\n            return '<li class=\"flex items-center justify-between gap-2 rounded-md bg-white px-3 py-2 text-base/6 text-zinc-700 ring-1 ring-zinc-200 dark:bg-zinc-950 dark:text-zinc-200 dark:ring-zinc-700 sm:text-sm/5\">' +\n                '<span class=\"font-semibold\">' + item.shortQuestion + '</span>' +\n                '<span class=\"text-zinc-500 dark:text-zinc-400\">Answer ' + item.correctAnswer + '</span>' +\n                '</li>';\n        }).join(\"\");\n    } else {\n        document.getElementById('quizMissedDetails').classList.add('hidden');\n        document.getElementById('quizMissedAnswers').innerHTML = \"\";\n    }\n\n    document.getElementById('quizSharePreview').innerText = shareText;\n    document.getElementById('quizShareStatus').innerText = \"\";\n    document.getElementById('quizResultModal').classList.remove('hidden');\n    document.body.classList.add('overflow-hidden');\n}\n\nfunction closeQuizModal() {\n    document.getElementById('quizResultModal').classList.add('hidden');\n    document.body.classList.remove('overflow-hidden');\n}\n\nfunction shareQuizOnX() {\n    var xPostUrl = \"https://x.com/intent/post?text=\" + encodeURIComponent(quizShareText + \"\\n\" + quizShareUrl);\n    window.open(xPostUrl, \"_blank\", \"noopener,noreferrer\");\n}\n\nfunction shareQuizWithSheet() {\n    var sharePayload = {\n        title: \"Swiftjective-C W.W.D.C. 2026 Pregame Quiz\",\n        text: quizShareText,\n        url: quizShareUrl\n    };\n    var fallbackText = quizShareText + \"\\n\" + quizShareUrl;\n    var shareStatus = document.getElementById('quizShareStatus');\n\n    if (navigator.share) {\n        navigator.share(sharePayload).then(function() {\n            shareStatus.innerText = \"\";\n        }).catch(function(error) {\n            if (error.name !== \"AbortError\") {\n                copyQuizResult(fallbackText, shareStatus, \"Share sheet failed. Result copied instead.\");\n            }\n        });\n        return;\n    }\n\n    copyQuizResult(fallbackText, shareStatus, \"Share sheet is not available here. Result copied instead.\");\n}\n\nfunction copyQuizResult(text, shareStatus, statusText) {\n    if (navigator.clipboard && navigator.clipboard.writeText) {\n        navigator.clipboard.writeText(text).then(function() {\n            shareStatus.innerText = statusText;\n        });\n        return;\n    }\n\n    window.prompt(\"Copy your result:\", text);\n}\n\ndocument.addEventListener('keydown', function(event) {\n  if (!document.getElementById('quizResultModal').classList.contains('hidden') && event.key === 'Escape') {\n    closeQuizModal();\n  }\n});\n</script>\n\n<!-- Quiz result sorta modal, nicer than an alert -->\n<div id=\"quizResultModal\" class=\"fixed inset-0 z-50 flex items-end justify-center bg-white/40 px-3 py-3 backdrop-blur-md dark:bg-zinc-950/50 sm:items-center sm:px-4 hidden\">\n  <div class=\"not-prose relative flex max-h-[calc(100dvh-1.5rem)] w-full max-w-lg flex-col overflow-hidden rounded-t-2xl bg-white text-left shadow-2xl dark:bg-zinc-900 sm:rounded-2xl\">\n    <div class=\"flex items-start justify-between gap-4 border-b border-zinc-950/10 px-5 py-4 dark:border-white/10\">\n      <div>\n        <p class=\"text-base/6 font-medium text-indigo-600 dark:text-indigo-300 sm:text-sm/5\">W.W.D.C. Pregame Quiz</p>\n        <h2 class=\"text-2xl font-semibold tracking-tight text-balance text-zinc-950 dark:text-zinc-50 sm:text-xl\">Quiz Results</h2>\n      </div>\n      <button onclick=\"closeQuizModal()\" class=\"relative inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full text-xl leading-none text-zinc-500 hover:bg-zinc-100 hover:text-zinc-800 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-100\" aria-label=\"Close\">\n        <span class=\"pointer-fine:hidden absolute left-1/2 top-1/2 h-12 w-12 -translate-x-1/2 -translate-y-1/2\" aria-hidden=\"true\"></span>\n        <span aria-hidden=\"true\">&times;</span>\n      </button>\n    </div>\n\n    <div class=\"overflow-y-auto px-5 py-4\">\n      <div class=\"grid grid-cols-3 divide-x divide-zinc-950/10 rounded-lg border border-zinc-950/10 dark:divide-white/10 dark:border-white/10\">\n        <div class=\"px-3 py-3\">\n          <p class=\"text-base/6 text-zinc-500 dark:text-zinc-400 sm:text-sm/5\">Score</p>\n          <p class=\"mt-1 whitespace-nowrap text-zinc-950 dark:text-zinc-50\">\n            <span id=\"quizScoreValue\" class=\"text-3xl font-semibold tracking-tight tabular-nums\">0</span>\n            <span class=\"text-base/6 text-zinc-500 dark:text-zinc-400 sm:text-sm/5\">/36</span>\n          </p>\n        </div>\n        <div class=\"px-3 py-3\">\n          <p class=\"text-base/6 text-zinc-500 dark:text-zinc-400 sm:text-sm/5\">Correct</p>\n          <p id=\"quizCorrectSummary\" class=\"mt-2 text-lg/6 font-semibold tabular-nums text-zinc-950 dark:text-zinc-50 sm:text-base/6\">0/15</p>\n        </div>\n        <div class=\"px-3 py-3\">\n          <p class=\"text-base/6 text-zinc-500 dark:text-zinc-400 sm:text-sm/5\">Missed</p>\n          <p id=\"quizMissedBadge\" class=\"mt-2 text-lg/6 font-semibold tabular-nums text-zinc-950 dark:text-zinc-50 sm:text-base/6\">0</p>\n        </div>\n      </div>\n\n      <div class=\"mt-4\">\n        <h3 class=\"text-base/6 font-semibold text-zinc-950 dark:text-zinc-50 sm:text-sm/5\">Round breakdown</h3>\n        <div id=\"quizRoundSummary\" class=\"mt-2 divide-y divide-zinc-950/10 rounded-lg border border-zinc-950/10 dark:divide-white/10 dark:border-white/10\"></div>\n      </div>\n\n      <details id=\"quizMissedDetails\" class=\"mt-4 border-t border-zinc-950/10 pt-3 dark:border-white/10\">\n        <summary class=\"cursor-pointer list-none text-base/6 font-semibold text-zinc-950 dark:text-zinc-50 sm:text-sm/5\">Review missed answers</summary>\n        <ul id=\"quizMissedAnswers\" class=\"mt-3 grid max-h-36 gap-2 overflow-y-auto sm:grid-cols-2\"></ul>\n      </details>\n\n      <div class=\"mt-4 border-t border-zinc-950/10 pt-3 dark:border-white/10\">\n        <h3 class=\"text-base/6 font-semibold text-zinc-950 dark:text-zinc-50 sm:text-sm/5\">Share preview</h3>\n        <div id=\"quizSharePreview\" class=\"mt-2 max-h-32 overflow-y-auto rounded-lg bg-zinc-50 p-3 font-mono text-base/7 text-zinc-800 ring-1 ring-zinc-950/10 dark:bg-zinc-800/60 dark:text-zinc-100 dark:ring-white/10 sm:text-sm/6\"></div>\n      </div>\n    </div>\n\n    <div class=\"grid gap-2 border-t border-zinc-950/10 bg-white px-5 py-4 dark:border-white/10 dark:bg-zinc-900 sm:grid-cols-2 sm:gap-3\">\n      <button id=\"quizShareXButton\" type=\"button\" onclick=\"shareQuizOnX()\" class=\"inline-flex min-h-11 items-center justify-center rounded-lg bg-black px-4 py-2.5 text-base/6 font-semibold text-white hover:bg-zinc-800 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-950 dark:bg-white dark:text-black dark:hover:bg-zinc-200 sm:min-h-10 sm:text-sm/5\">Share on X</button>\n      <button id=\"quizShareSheetButton\" type=\"button\" onclick=\"shareQuizWithSheet()\" class=\"inline-flex min-h-11 items-center justify-center rounded-lg bg-indigo-50 px-4 py-2.5 text-base/6 font-semibold text-indigo-700 hover:bg-indigo-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500 dark:bg-indigo-400/10 dark:text-indigo-200 dark:hover:bg-indigo-400/20 sm:min-h-10 sm:text-sm/5\">Share.Sheet()</button>\n      <p id=\"quizShareStatus\" class=\"min-h-6 text-center text-base/6 text-zinc-500 dark:text-zinc-400 sm:col-span-2 sm:min-h-0 sm:text-sm/5\" aria-live=\"polite\"></p>\n    </div>\n\n  </div>\n</div>\n\n<h3 id=\"answer-key\">Answer Key</h3>\n\n<p><b>Round 1:</b></p>\n\n<ol>\n  <li>B. The Mobile Software Competition Act. Apple says iOS 26.2 introduced the Japan changes to comply with the MSCA. <a href=\"https://developer.apple.com/support/app-distribution-in-japan/\">1</a></li>\n  <li>B. Guideline 1.2, User-Generated Content. Random or anonymous chat now gets pulled under that umbrella. <a href=\"https://developer.apple.com/news/?id=d75yllv4\">2</a></li>\n  <li>D. Apps in a bundle no longer need to support the same platform as the primary app for bundles created on February 17, 2026 or later. <a href=\"https://developer.apple.com/help/app-store-connect/release-notes/\">3</a></li>\n  <li>A. The United States and Singapore. Outside those two storefronts, monthly subscriptions can now have a 12-month commitment. <a href=\"https://developer.apple.com/help/app-store-connect/release-notes/\">3</a></li>\n  <li>Wildcard: C. Promo codes for In-App Purchases are no longer supported. Pour one out for the old tiny-code economy. <a href=\"https://developer.apple.com/help/app-store-connect/release-notes/\">3</a></li>\n</ol>\n\n<p><b>Round 2:</b></p>\n\n<ol>\n  <li>C. 256GB. The 17e starts with double the previous generation’s entry storage. <a href=\"https://www.apple.com/newsroom/2026/03/apple-introduces-iphone-17e/\">4</a></li>\n  <li>C. A18 Pro. Yes, the footnote really does say preproduction MacBook Neo systems with Apple A18 Pro. <a href=\"https://www.apple.com/newsroom/2026/03/macbook-neo-iphone-17e-ipad-air-with-m4-and-more-are-now-available/\">5</a></li>\n  <li>D. N1 and C1X. Wi-Fi 7, Bluetooth 6, Thread and cellular modem trivia all in one tidy pair. <a href=\"https://www.apple.com/newsroom/2026/03/apple-introduces-the-new-ipad-air-powered-by-m4/\">6</a></li>\n  <li>C. Sage. Apple lists MacBook Neo in silver, blush, citrus and indigo, which means Sage is the very tasteful impostor. <a href=\"https://www.apple.com/newsroom/2026/03/macbook-neo-iphone-17e-ipad-air-with-m4-and-more-are-now-available/\">5</a></li>\n  <li>Wildcard: A. A lime and a lemon. Sometimes product marketing is just a tiny citrus FaceTime call on main. <a href=\"https://www.tiktok.com/@apple/video/7613820709629971725\">7</a>, <a href=\"https://www.reddit.com/r/apple/comments/1rmv3zr/apple_is_on_tiktok_posting_unhinged_videos_about/\">8</a></li>\n</ol>\n\n<p><b>Round 3:</b></p>\n\n<ol>\n  <li>A. San Pedro Square Market. The 2026 pre-W.W.D.C. community gathering listing puts the ritual right at 87 N San Pedro St, patio and all. <a href=\"https://luma.com/trtbdihd\">13</a></li>\n  <li>B. Weezer. W.W.D.C. 2019’s Bash at Discovery Meadow featured the multi-platinum alt-rock heroes themselves. <a href=\"https://9to5mac.com/2019/06/06/wwdc-bash-2019/\">9</a></li>\n  <li>A. A mechanical feeding arm controlled with head movements. Ternus’s Penn senior project was built for people with quadriplegia, which is vastly more interesting than another succession answer. <a href=\"https://en.wikipedia.org/wiki/John_Ternus\">10</a></li>\n  <li>C. genai.apple.com. A dormant Apple subdomain with “genai” in the name is exactly the kind of nothing that becomes pre-W.W.D.C. something. <a href=\"https://www.macrumors.com/2026/05/23/apple-gen-ai-subdomain/\">11</a></li>\n  <li>Wildcard: C. Spatial Computing. It sounds like it should be a category, but the 2026 list is Delight and Fun, Inclusivity, Innovation, Interaction, Social Impact, and Visuals and Graphics. <a href=\"https://developer.apple.com/design/awards/\">12</a></li>\n</ol>",
            "summary": "Tern up for what! They’ll never Ternus against each other! Okay. Sorry. I’m done now. But it is that time…",
            "image": "https://swiftjectivec.com/assets/images/pregamequiz_2026.png",
            "date_published": "2026-05-26T00:00:00-05:00",
            "date_modified": "2026-05-26T00:00:00-05:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["Trivia"]},{
            "id": "https://swiftjectivec.com/WWDC-Wish-List-2026",
            "url": "https://swiftjectivec.com/WWDC-Wish-List-2026/",
            "title": "WWDC in a 2026 Landscape",
            "content_html": "<p>This W.W.D.C. <em>will</em> probably be unlike any other. Things are going a bit wild lately, and even ardent A.I. detractors would likely concede that’s undeniably true now. The way we work compared to a year ago is drastically different. And, even six months ago? Might as well be a lifetime.</p>\n\n<p>Cupertino &amp; Friends™️ would do well to adapt to a rapidly changing landscape. I’m hopeful they will, too, if recent trends are any indication. We received <a href=\"https://www.swiftjectivec.com/Agentic-Coding-Codex-Claude-Code-in-Xcode/\">agentic support in Xcode</a> not long ago, something typically reserved #ForTheKeynote.</p>\n\n<p>In the world of 2026, here’s what I’d love to see:</p>\n\n<ul>\n  <li><strong>The usual fare:</strong> Video sessions, in-depth deep dives, the works. Let’s not forget that Apple has done a fantastic job at packaging these now. Closed captions, links to demo projects, and other relevant materials are all tidy and available in the developer app. But in today’s world, stopping here would be a missed opportunity.</li>\n  <li><strong>Skills:</strong> Consider this — each dub dub session which presents a new API comes packaged with a skill. That would be incredible. In fact, Apple has kinda sorta already <a href=\"https://mastodon.social/@steipete/114982119853883518\">done this</a>, but it was tucked away deep in the file system. Don’t make me poke around, link a skill with each dub dub session.</li>\n  <li><strong>MCP:</strong> Depending on who you ask, MCPs are amazing or terrible token wasters on their way out. Regardless, I’d love a direct, official line to Apple’s docs. For now, ex-Apple employee and NSHipter stalwart <a href=\"https://x.com/mattt\">Mattt</a> has the best solution with <a href=\"https://sosumi.ai\">sosumi</a>.</li>\n  <li><strong>Xcode:</strong> And, Xcode should lean into agentic engineering, whatever that looks like. I still use an IDE quite frequently, and that’s certainly true of iOS development. There is not one piece of software I could ship that hasn’t had my fingerprints on it. Little tweaks, the UI and UX, all layers I am unwilling to concede to AI.</li>\n</ul>\n\n<p>In short, I hope Apple helps me do two things: adopt the latest APIs, and do that quickly. All of the above would help.</p>\n\n<p>Code and implementation were always the time sink. They don’t have to be anymore. If using agents puts you in a state of torpor, that’s a shame. Instead, use them to get into a loop of build, review, and refine as quickly as you can so that you can make your apps the absolute best they can be. Let me stand up a working draft, and then let me make it great.</p>\n\n<p>Until next time ✌️</p>",
            "summary": "This W.W.D.C. will probably be unlike any other. Things are going a bit wild lately, and even ardent A.I. detractors would likely concede that’s undeniably true now. The way we work compared to a year ago is drastically different. And, even six months ago? Might as well be a lifetime.",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-05-16T00:00:00-05:00",
            "date_modified": "2026-05-16T00:00:00-05:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["The Indie Dev Diaries"]},{
            "id": "https://swiftjectivec.com/Along-the-Way",
            "url": "https://swiftjectivec.com/Along-the-Way/",
            "title": "Along the Way",
            "content_html": "<p>Do you know <a href=\"https://mastodon.social/@atow\">Adam Tow</a>?</p>\n\n<p>If not, you definitely should - he has some fantastic stories to tell. Did you know he once ran into Steve Jobs at a Sushi takeout restaurant which later led to a fairly in-depth email exchange between the two of them about the Newton? Or, that he organized a <em>Newton protest outside of Apple</em>? I learned all this from this recent talk at <a href=\"https://deepdishswift.com\">Deep Dish Swift 26’</a>, and it was a delight.</p>\n\n<p>Or, how about our favorite neighborhood alternative App Store developer <a href=\"https://x.com/rileytestut\">Riley</a>? He has battled Apple tooth and nail, and somehow came out on the other side. Armed with the wit and determination only found in a man who has the patience to actually <em>make</em> another App Store, his recount of how it was all finally approved is simply hilarious. In short, he basically gave Apple an ultimatum on which of his two apps they should accept during a long notarization process. I won’t spoil it, you should just watch the talk. Especially if you’ve ever been burned by App Review, you’ll find a little poetic justice somewhere in there.</p>\n\n<p>…and I, of course, could go on. So many great talks, and even better people.</p>\n\n<p>This week, I began to realize I’ve…kinda been around the iOS scene awhile now? Ya know? Like, I’m not new here anymore. If you will allow it, here’s how my oldest looked when I first started on Spend Stack, and what he looks like now:</p>\n\n<div class=\"image-comparison-wrapper rounded-xl not-prose\">\n  <div class=\"relative w-full overflow-hidden image-comparison-slider\" id=\"imageComparisonSlider\">\n    <img src=\"../assets/images/ut_3.jpeg\" alt=\"Image 1\" class=\"w-full h-auto rounded-xl\" />\n    <div class=\"absolute top-0 left-0 w-full h-full overflow-hidden\" id=\"imageWrapper\">\n      <img src=\"../assets/images/ut_2.jpeg\" alt=\"Image 2\" class=\"absolute top-0 left-0 w-full h-full object-cover rounded-xl\" />\n    </div>\n    <div class=\"slider-handle\" id=\"sliderHandle\">\n      <div class=\"slider-button\">\n        <div class=\"flex\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"h-4 w-4\">\n                <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n              </svg>\n              <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"h-4 w-4\">\n                <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n              </svg>             \n        </div>\n      </div>\n    </div>\n    \n      <div class=\"caption-container rounded-xl\">\n        <div class=\"caption caption-left sjc-prose\" id=\"caption1\">Tiny Benny</div>\n        <div class=\"caption caption-right sjc-prose\" id=\"caption2\">Not-Tiny Benny</div>\n      </div>\n    \n  </div>\n</div>\n\n<style>\n  .image-comparison-wrapper {\n    position: relative;\n    user-select: none;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n  }\n\n  .image-comparison-slider {\n    position: relative;\n    z-index: 0;\n  }\n\n  .slider-handle {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    width: 4px;\n    background: white;\n    cursor: ew-resize;\n    z-index: 10;\n  }\n\n  .slider-button {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    width: 40px;\n    height: 40px;\n    background: white;\n    border-radius: 50%;\n    transform: translate(-50%, -50%);\n    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n\n  .slider-icon {\n    width: 24px;\n    height: 24px;\n    color: #333; /* Adjust color as needed */\n  }\n\n  .caption-container {\n    position: absolute;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    display: flex;\n    justify-content: space-between;\n    padding: 10px;\n    background: rgba(255, 255, 255, 0.7);\n    backdrop-filter: blur(10px);\n    -webkit-backdrop-filter: blur(10px);\n  }\n\n  .caption {\n    padding: 10px 15px;\n    color: black;\n    font-size: 14px;\n    max-width: 45%;\n    overflow: hidden;\n    transition: opacity 0.3s ease;\n  }\n\n  .caption-left {\n    text-align: left;\n  }\n\n  .caption-right {\n    text-align: right;\n  }\n</style>\n\n<script>\ndocument.addEventListener('DOMContentLoaded', function() {\n  const slider = document.getElementById('imageComparisonSlider');\n  const sliderHandle = document.getElementById('sliderHandle');\n  const imageWrapper = document.getElementById('imageWrapper');\n  const caption1 = document.getElementById('caption1');\n  const caption2 = document.getElementById('caption2');\n  let isDragging = false;\n  let currentX;\n\n  function updateSliderPosition() {\n    if (!isDragging && currentX === undefined) return;\n\n    const sliderRect = slider.getBoundingClientRect();\n    let position = (currentX - sliderRect.left) / sliderRect.width;\n    position = Math.max(0, Math.min(position, 1));\n\n    sliderHandle.style.left = `${position * 100}%`;\n    imageWrapper.style.clipPath = `inset(0 ${100 - position * 100}% 0 0)`;\n\n    // Update caption opacity\n    if (caption1 && caption2) {\n      const minOpacity = 0.20;\n      const maxOpacity = 1;\n      const opacityRange = maxOpacity - minOpacity;\n\n      let opacity1 = minOpacity + opacityRange * (1 - position);\n      let opacity2 = minOpacity + opacityRange * position;\n\n      caption1.style.opacity = opacity1;\n      caption2.style.opacity = opacity2;\n    }\n\n    requestAnimationFrame(updateSliderPosition);\n  }\n\n  function startDragging(e) {\n    isDragging = true;\n    currentX = e.clientX || e.touches[0].clientX;\n    requestAnimationFrame(updateSliderPosition);\n  }\n\n  function stopDragging() {\n    isDragging = false;\n    currentX = undefined;\n  }\n\n  function onMove(e) {\n    if (!isDragging) return;\n    currentX = e.clientX || e.touches[0].clientX;\n  }\n\n  sliderHandle.addEventListener('mousedown', startDragging);\n  sliderHandle.addEventListener('touchstart', startDragging);\n\n  document.addEventListener('mousemove', onMove);\n  document.addEventListener('touchmove', onMove, { passive: false });\n\n  document.addEventListener('mouseup', stopDragging);\n  document.addEventListener('touchend', stopDragging);\n\n  slider.addEventListener('click', function(e) {\n    currentX = e.clientX;\n    requestAnimationFrame(updateSliderPosition);\n  });\n\n  // Initialize slider position\n  currentX = slider.getBoundingClientRect().left + slider.offsetWidth / 2;\n  requestAnimationFrame(updateSliderPosition);\n});\n</script>\n\n<p><em>🥹 They grow up so fast!</em></p>\n\n<p>And, as the years tick on, as they do for all of us, life thankfully starts to arm you with more wisdom, perspectives on life, and new angles to look at things. In an industry where, currently, everything is changing, we tend to forget the best part of any app — it’s the person behind it.</p>\n\n<p>This is the primary reason I lament Apple’s modern approach to W.W.D.C. — the community is <em>fractured</em> at the one single time during the year when it should be united most. Going to Apple Park, I’m sure, is a fantastic experience for the few who win the lottery. Though, it’s nothing compared to when seemingly every single person in this industry was in one central place.</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/ut_1.jpeg\" role=\"presentation\" srcset=\"../assets/images/ut_1.jpeg\" alt=\"WWDC 2019.\" /></p>\n\n<p>AltConf going on next door, running down the halls of San Jose convention center, packed with iOS developers, designers, and Apple employees — you just can’t beat it. Every year, I plead with Apple on the developer survey to go back to this. I don’t think they ever will, though. And that’s a shame, because the relationships you formed, the people you met, the kind folks at Apple you could network with, all of those things could change the trajectory of your career. The best parts I’m talking about.</p>\n\n<p>And, it’s the same still with social media. Twitter, in the before times, was a community and it felt like we were all there. Now, that’s obviously fractured too. Some are on Mastodon, others on Threads, a few kicking around on BlueSky, more still on X, etc. It’s changed quite a bit. For me? It was surreal to realize how others associate me with certain chapters of my career. Some personally know me from Spend Stack. Others, it’s the book series. Yet again, there’s more who associate me with Alyx or Elite Hoops. And, yeah, some hotshot bros know me as a <a href=\"https://x.com/farrux_hewson/status/2042201541923467373?s=20\">vibe coder noob apparently</a>. And honestly? I enjoy meeting every single one of them.</p>\n\n<p>Where was I going with this again?</p>\n\n<p>Oh yes — the people! The relationships. Events, social media, the places we can go, the way dub dub is held — all of that stuff will always change. No matter the landscape, though, I would encourage you to get around your people at least once a year if you can. Your other indie friends, the ones who work at giant companies, new kids on the scene eager to learn and show off their app. We don’t wake up and decide to start in this career <em>just</em> to met new people, it’s not <em>why</em> we do this, but it is certainly the best part.</p>\n\n<p>Until next time ✌️</p>",
            "summary": "Do you know Adam Tow?",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-04-15T00:00:00-05:00",
            "date_modified": "2026-04-15T00:00:00-05:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["The Indie Dev Diaries"]},{
            "id": "https://swiftjectivec.com/Kids-and-Vibe-Coding-iOS-Apps",
            "url": "https://swiftjectivec.com/Kids-and-Vibe-Coding-iOS-Apps/",
            "title": "Kids and Vibe Coding: The Joy of Building",
            "content_html": "<p>Ah, the joy of building. Lately, my kids have acquired <em>the bug</em>. Now that they are a bit older, they’ve started to somewhat realize what I’m doing all day long, hunched over a brightly lit laptop — pecking away on a keyboard.</p>\n\n<p>Click clack, clack clack, click click….<strong>boom</strong>, I made something. An app appears, and now they are at the age where they can comprehend that. And, well, they think that is amazing.</p>\n\n<p>And thus, I’ve started to dip into the realm of kids and vibe coding. At first, I had an outline with something to say on this topic. But, you know what, I just threw it out. Both of my oldest kiddos, Benny (12) and Remy (9), have asked me to help them “make an app”, and we’ve had a blast.</p>\n\n<p>What follows are just random observations in no particular order.</p>\n\n<h3 id=\"they-have-no-idea-what-theyre-doing\">They have no idea what they’re doing</h3>\n\n<p>What even <em>is</em> an app to a kid? To them, anything entirely web-based for the whole experience is not an app (I raised them right!), and they were even surprised you could charge money on the web!</p>\n\n<p>But, we all start somewhere. And, to that end, they’ve both taken completely different approaches to deciding where they should start. Remy, ever the analytical thinker among my kids, opted to spec it out. Benny? Two sheets to the wind, he just opened up Codex and let it rip. Which leads me to my first observation…</p>\n\n<h3 id=\"the-prompts-are-just-brutal\">The prompts are just brutal</h3>\n\n<p>…and it’s somewhat endearing at the same time. Seeing Remy hunched over the keyboard, pecking away on one hand:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/remy_tcg1.jpg\" role=\"presentation\" srcset=\"../assets/images/remy_tcg1.jpg\" alt=\"Remy typing on a keyboard on a kitchen counter.\" /></p>\n\n<p>…just tossing Codex the most open-ended instructions imaginable:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/remy_tcg2.jpg\" role=\"presentation\" srcset=\"../assets/images/remy_tcg2.jpg\" alt=\"An open-ended prompt for an LLM to make a Pokemon app.\" /></p>\n\n<p>So many questions! What kind of app? Which platform? FIVE BUCKS? We using StoreKit for this, what about paywalls? The seasoned engineer in me reeled, but I wanted them to hit as many bumps and learn how to work around them as they could. Even then, though, they do get “Dad Assists” here and there. And, Remy used his to kickstart his project:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/remy_tcg3.jpg\" role=\"presentation\" srcset=\"../assets/images/remy_tcg3.jpg\" alt=\"A more in-depth follow up to the previous prompt.\" /></p>\n\n<p>In this case, I mentioned he might want to say what kind of app it is, punt the money stuff for now, and hint to the LLM which general direction we’re taking things (iOS, minimum target is likely iOS 26).</p>\n\n<p>Writing prompt cleanups have been fantastic learning and bonding moments. We get to briefly talk about why I wrote something the way I did, I try to gently explain how an LLM works, what they’re good at, what they’re not as good at, etc.</p>\n\n<p>To that end, their prompts have improved. But even then…</p>\n\n<h3 id=\"ohhhh-my-the-ux\">Ohhhh my, the UX</h3>\n\n<p>…these apps are <em>brutal</em> right now. Remy’s has, like, three search functions - all doing different things. I mean, check this number out:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/remy_tcg4.jpg\" role=\"presentation\" srcset=\"../assets/images/remy_tcg4.jpg\" alt=\"Remy's Pokemon app.\" /></p>\n\n<p>It’s easy for <em>us</em> to spot the issues. However, the bit that’s surprised me, though, is that they are…aware of it? Even as a 9 year old. Is this a potential byproduct of growing up in the digital age? They know it doesn’t feel right, and they can’t really say why yet, they just know it feels off.</p>\n\n<p>That’s hardly surprising, as design and user experience are things that take years and years to develop.</p>\n\n<h3 id=\"their-imagination-is-on-steroids\">Their imagination is on steroids</h3>\n\n<p>The fact that they now live in a world where they can type in a box and get something working has, quite literally, ignited their creativity, curiosity, and excitement. The boys are huge fans of <a href=\"https://neal.fun\">neal.fun</a>, especially his fantastic auction game:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/remy_tcg5.jpg\" role=\"presentation\" srcset=\"../assets/images/remy_tcg5.jpg\" alt=\"neal.fun's auction game.\" /></p>\n\n<p>Remy, unshackled with unimaginable power at his disposal, immediately u-turned on a bug fix and just threw that at Codex and instructed it to add a Pokemon card version in his app. And, it came pretty close one-shotting it:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/remy_tcg7.jpg\" role=\"presentation\" srcset=\"../assets/images/remy_tcg7.jpg\" alt=\"Remy's version of an auction game\" /></p>\n\n<p>This is the good stuff. Being able to think of something fun and have it come to life. It’s the same dopamine hit you get from building with legos, finishing a picture, or generally constructing a thought and turning it into something tangible. While it’s silly in this context, these are the moments that will inspire them to continue.</p>\n\n<h3 id=\"the-skills-still-pay\">The skills still pay</h3>\n\n<p>The one ephiphany I’ve had with all of this (aside from how insane it is that my kids can get a functioning app working) is that the skills we have are magnified now, perhaps more than ever. We’ve all been so uneasy about the implication of “anyone can make an app”, we haven’t stopped much to consider that our hard-earned skills are still the thing that makes a good app.</p>\n\n<p>You can throw all the skill files you want at an LLM (And you should! They’re great!), but they still have critical limitations. Take text, for example. What would you instinctively do if you have a view whose text was truncated, clipping, or otherwise not fitting into a container?</p>\n\n<p>The layman would say, “Can you make this text not clip?” The hardened iOS veteran might say, “Apply a .minimumScaleFactor modifier to this text, and ensure you’re using a Text style and not hard coding the font size.”</p>\n\n<p>Off the cuff? Visually, you may get the same result at first. But, well — if you know, you know. One is objectively better. And those of us who can speak the language will still be making the best apps. The same skills still win, <a href=\"https://www.swiftjectivec.com/The-Abstraction-Layer/\">as I mentioned before</a>, the tools have simply changed. It does, however, highlight my one lingering worry: That the next generation my take an ignorance through obstinance stance towards coding. If the ease of it all could tempt a kid (or anyone) to never bother learning how something truly works, they’d be missing out on some required skills.</p>\n\n<h3 id=\"the-sweet-spot\">The sweet spot</h3>\n\n<p>While the kids have been using Codex, I think I’d opt to stick them in <a href=\"https://bitrig.com\">Bitrig’s nascent mac app</a>. It’s a bit more harnessed, in a good way, and I think the results would be a little better. The app Anything spun something up quick, in Expo. With Codex, I have a ton of credits, so we’ve stuck with that. Personally? I prefer Codex for coding anyways, especially since they put a frontend on top of the CLI. If it becomes a native mac app, I’ll probably never close it.</p>\n\n<p>But for them? I can’t stop thinking about how a Macbook Neo with Bitrig would be a fun addition to the Morgan family. You kinda sorta need to make sure these kids don’t blow up your house with this stuff, which, well, depending on your permissions — could certainly happen.</p>\n\n<h3 id=\"wrapping-up\">Wrapping up</h3>\n\n<p>Reflecting on the vibe coding experiences with the kids, I only have one prevailing thought: we are all having so much <em>fun</em>. The kids are becoming increasingly interested in what their dad actually does for a career now. Remy, especially, is getting into it. He’s developed the ineluctable urge to <em>make something</em>. The last two days he has come home from school, it’s “Dad, can I work on my app!?” He even stuck some post-it notes to his closet so he wouldn’t forget what to work on the next day:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/remy_tcg6.jpg\" role=\"presentation\" srcset=\"../assets/images/remy_tcg6.jpg\" alt=\"Month of marketing gameplan.\" /></p>\n\n<p>Until next time ✌️</p>",
            "summary": "Ah, the joy of building. Lately, my kids have acquired the bug. Now that they are a bit older, they’ve started to somewhat realize what I’m doing all day long, hunched over a brightly lit laptop — pecking away on a keyboard.",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-04-08T00:00:00-05:00",
            "date_modified": "2026-04-08T00:00:00-05:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["A.I."]},{
            "id": "https://swiftjectivec.com/The-Abstraction-Layer",
            "url": "https://swiftjectivec.com/The-Abstraction-Layer/",
            "title": "The Abstraction Layer",
            "content_html": "<p>When I first began my degree in the field of CompSci, I picked up a book: <a href=\"https://www.amazon.com/Code-Language-Computer-Hardware-Software/dp/0137909101\">“Code”, by Charles Petzold</a>. I don’t distinctly remember if it necessarily changed my life or sparked my love of software development. But, I remember with certainty that it <em>did</em> give me the gift of curiosity.</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/code_cp.png\" role=\"presentation\" srcset=\"../assets/images/code_cp.png\" alt=\"Code by Charles Petzold.\" /></p>\n\n<p>What was actually happening when I was typing in Visual Basic on some Windows desktop in a computer lab at Ozarks Technical Community College? How did the characters transform and…just…<em>do stuff</em>? I wanted to know, and that book went in on it all. I remember learning about how every computer begins with simple, basic physical states: on and off. Open, and closed. And, of course, 1 or 0.</p>\n\n<p>From there, those binary states can be represented by all sorts of interesting modes: switches, relays, and then transistors. Building on that some more, wire enough of them together and now we get to the interesting stuff. Logic gates, adders, memory, clocks, and eventually down the line — a CPU that can read instructions from memory! And, execute them!</p>\n\n<p>But in my day to day? That’s all abstracted away from me, as it should be. It’s just as well, though, since abstractions have long been a core part of our indsutry. In fact, who remembers interviews in the aughts when object orientated programming was king? We had to remember our favorite acronym, A.P.I.E. — <em>abstraction</em>, polymorphism, inheritance, and encapsulation. So, in that sense, code has long been an abstraction layer. It’s one that sits comfortably above the raw hardware, <em>but</em> it’s close enough that, after enough of said translation, it can still make silicon do something real and tangible in the world.</p>\n\n<p>I’ve been thinking a lot about abstraction layers lately.</p>\n\n<p>What the “abstraction” layer is now, and how we define it, is changing. And, naturally, it has me wondering. With the rise of agentic engineering, I’ve started to consider something I thought impossible only a few years ago:</p>\n\n<p><span class=\"relative inline-block not-prose pb-2 md:pb-[0.25px]\"><span class=\"bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-purple-500 font-semibold\">Is code going to be abstracted away, entirely, soon?</span><span class=\"absolute left-0 bottom-0 w-full h-1.5\" style=\"background-image: url(&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 6' preserveAspectRatio='none'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0%25' y1='0%25' x2='100%25' y2='0%25'%3E%3Cstop offset='0%25' stop-color='%233b82f6'/%3E%3Cstop offset='100%25' stop-color='%238b5cf6'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M0,6 Q50,0 100,6' fill='none' stroke='url(%23g)' stroke-width='1.75'/%3E%3C/svg%3E&quot;); background-size: 100% 100%; background-repeat: no-repeat;\"></span></span></p>\n\n<p>And, yeah, I realize the word “soon” is doing some <em>heavy lifting</em> here.</p>\n\n<p>Once the frontier models improve, <em>how soon until it matters if you read what it outputs?</em> No, seriously, I’m wondering that lately. I know, I know — <strong>I KNOW</strong> — it’s not there yet. Today. But, I think eventually, it will be. And what does that mean for software engineering? Is it then prompt engineering? Will knowing how the all the pieces fit together matter even more, or less?</p>\n\n<p>How much longer is understanding code a competitive advantage? I know it certainly is today. And, lest I’m not making my stance clear enough, you <em>do need</em> to understand code to succeed in my opinion. In 2026, most of us in this field grew up figuring out its intimate inner workings. That’s why those with years of experience are currently building software at a blistering pace. Though, how long will it keep us ahead of everyone else? Because when it becomes abstracted away, well — that’s a different world we’ll live in.</p>\n\n<section class=\"bg-indigo-50 border-l-8 border-indigo-500 text-gray-800 rounded-md my-10 dark:text-gray-300 dark:bg-gray-600 dark:border-indigo-700 \">\n    <div class=\"px-5 font-mono\">\n        <p class=\"pt-2 md:pt-4\"><span class=\"text-purple-600 dark:text-purple-400\">let</span> concatenatedThoughts = <span class=\"text-red-600\">\"\"\"</span></p>\n        <p class=\"text-gray-600 dark:text-gray-300 text-sm md:text-base\">Of course, we will always need people in the world who understand code. In the same way that we need people in the world who have a professional, expert knowledge of how computers actually work. We can't afford to lose that, obviously, because when one machine drives another — both machines will always need a captain.</p>\n        <p class=\"pb-2 md:pb-4 text-gray-600 text-base\"><span class=\"text-red-600\">\"\"\"</span></p>\n    </div>\n</section>\n\n<p>I’m pondering here, not panicking. We need to remember that abstraction layers are not inherently bad. In fact, by most measures, not only are they incredibly useful — they are necessary. I don’t want to manually tweak logic gates. I want to write code to do it. Years ago, there was undoubtedly a time where <em>writing</em> code woud seem as outlandish as using a chat interface to produce that same code for you.</p>\n\n<p>Naturally, as the future progresses and technology advances, making software will look different, too. The future of software engineering versus “AI does it all” hopefully will not be a zero-sum game. More abstraction does not <em>automatically</em> mean we need less understanding, but I think it does most likely change “what” is important to understand.</p>\n\n<p>I don’t know the answer, and to be honest — I’m not scared of the answer, either. I’ve made my way in this industry by being curious. People like to say it’s all changing so fast, and there’s an inordinate amount of AI tooling, advances, or models to learn. I say it’s always been that way. I’ve done well in this career because of adapting to changes. By wondering how logic gates, bits and bytes, and code eventually create a piece of software I made. And whatever the tools and technology become to keep creating those things well and with precision, I’ll keep learning.</p>\n\n<p>When I went back to speak at my community college years ago, I told the prospective students that the only constant in our industry is change. Now, I suppose, never has that been more apt.</p>\n\n<p>Until next time ✌️</p>",
            "summary": "When I first began my degree in the field of CompSci, I picked up a book: “Code”, by Charles Petzold. I don’t distinctly remember if it necessarily changed my life or sparked my love of software development. But, I remember with certainty that it did give me the gift of curiosity.",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-03-20T00:00:00-05:00",
            "date_modified": "2026-03-20T00:00:00-05:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["A.I."]},{
            "id": "https://swiftjectivec.com/Agentic-Coding-Codex-Claude-Code-in-Xcode",
            "url": "https://swiftjectivec.com/Agentic-Coding-Codex-Claude-Code-in-Xcode/",
            "title": "Agentic Coding in Xcode 26.3 with Claude Code and Codex",
            "content_html": "<p>I was filled with whimsy watching OpenAI announce their Codex app<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">1</a></sup> not even <a href=\"https://x.com/JordanMorgan10/status/2018401840497410297\">two days ago</a>. But life comes at you fast. The very next day, <a href=\"https://x.com/JordanMorgan10/status/2018764327051035035\">Xcode 26.3 dropped with support for agentic coding</a>.</p>\n\n<p>As someone who is truly enjoying using agents to create software, I was ready to dive in. I’ve come to love using agents in Terminal, but I’m always up to try the shiny new thing. And if there’s something Apple does particularly well, it’s typically integrating new shiny things with a refined taste to them.</p>\n\n<p>Here, I’ll share first impressions, and some important answers to questions I had. Also, I’ll be primarily chatting through the Codex lens.</p>\n\n<h3 id=\"the-critical-infrastructure\">The Critical Infrastructure</h3>\n\n<p>Ask three different people how they use agents, and somehow you’ll get sixteen different answers. Me? I rely on the “core pillars”:</p>\n\n<ol>\n  <li><strong>agents.md</strong>: Projects I use all have a lightweight <code class=\"language-plaintext highlighter-rouge\">agents.md</code> or <code class=\"language-plaintext highlighter-rouge\">claude.md</code> file. Critical to how I work.</li>\n  <li><strong>skills.md</strong>: The more nascent skills movement just keeps growing. Vercel, and its successful <a href=\"https://skills.sh\">skills.sh</a> initiative, has only strengthened it. I’ve come to use several skills, and not having those would be a quick stop for me.</li>\n  <li><strong>MCPs</strong>: The model context protocol is amazing to interface with services. When they were first announced, I thought of them as nothing more than an API. And, in some ways, that is true. But they aren’t APIs for you or me, they are for agents. Supabase’s MCP has saved me tons of time, “Query all of the basketball drills for this User ID”, “Do I have cascade deletes in place for X or Y”, the list goes on. They are a requirement for my agent use.</li>\n</ol>\n\n<p>If Xcode’s integration couldn’t leverage <em>any</em> one of these, I would personally have no reason to use it. I nearly moved on altogether since I realized the star of the show, Apple’s own Xcode MCP implementation, is available for other agents to use:</p>\n\n<div class=\"language-bash highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code><span class=\"c\"># CC:</span>\nclaude mcp add <span class=\"nt\">--transport</span> stdio xcode <span class=\"nt\">--</span> xcrun mcpbridge\n\n<span class=\"c\"># Codex:</span>\ncodex mcp add xcode <span class=\"nt\">--</span> xcrun mcpbridge\n</code></pre></div></div>\n\n<p>Still, the allure of keeping things “in house” is strong. And, Apple is only going to improve their offering. As long as my core pillars were usable, I’d try it out. At first, I thought that wasn’t the case (my skills weren’t showing, for example) but I’m happy to report that it can, and does, use your existing “core pillars” with a little pageantry from your end.</p>\n\n<h3 id=\"new-codex\">New Codex</h3>\n\n<p>Here’s what made it all click for me. <strong>If you already have Codex installed, think of Xcode’s Codex usage as an entirely fresh install.</strong> That makes complete sense when you zoom out and think about it (this Codex is literally for Apple development and nothing else). You can confirm this for yourself by viewing the <code class=\"language-plaintext highlighter-rouge\">config.toml</code> for each installation:</p>\n\n<div class=\"image-comparison-wrapper rounded-xl not-prose\">\n  <div class=\"relative w-full overflow-hidden image-comparison-slider\" id=\"imageComparisonSlider\">\n    <img src=\"../assets/images/agentic_apple.jpg\" alt=\"Image 1\" class=\"w-full h-auto rounded-xl\" />\n    <div class=\"absolute top-0 left-0 w-full h-full overflow-hidden\" id=\"imageWrapper\">\n      <img src=\"../assets/images/agentic_mine.jpg\" alt=\"Image 2\" class=\"absolute top-0 left-0 w-full h-full object-cover rounded-xl\" />\n    </div>\n    <div class=\"slider-handle\" id=\"sliderHandle\">\n      <div class=\"slider-button\">\n        <div class=\"flex\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"h-4 w-4\">\n                <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n              </svg>\n              <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"h-4 w-4\">\n                <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n              </svg>             \n        </div>\n      </div>\n    </div>\n    \n      <div class=\"caption-container rounded-xl\">\n        <div class=\"caption caption-left sjc-prose\" id=\"caption1\">My own config</div>\n        <div class=\"caption caption-right sjc-prose\" id=\"caption2\">Apple's config</div>\n      </div>\n    \n  </div>\n</div>\n\n<style>\n  .image-comparison-wrapper {\n    position: relative;\n    user-select: none;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n  }\n\n  .image-comparison-slider {\n    position: relative;\n    z-index: 0;\n  }\n\n  .slider-handle {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    width: 4px;\n    background: white;\n    cursor: ew-resize;\n    z-index: 10;\n  }\n\n  .slider-button {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    width: 40px;\n    height: 40px;\n    background: white;\n    border-radius: 50%;\n    transform: translate(-50%, -50%);\n    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n\n  .slider-icon {\n    width: 24px;\n    height: 24px;\n    color: #333; /* Adjust color as needed */\n  }\n\n  .caption-container {\n    position: absolute;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    display: flex;\n    justify-content: space-between;\n    padding: 10px;\n    background: rgba(255, 255, 255, 0.7);\n    backdrop-filter: blur(10px);\n    -webkit-backdrop-filter: blur(10px);\n  }\n\n  .caption {\n    padding: 10px 15px;\n    color: black;\n    font-size: 14px;\n    max-width: 45%;\n    overflow: hidden;\n    transition: opacity 0.3s ease;\n  }\n\n  .caption-left {\n    text-align: left;\n  }\n\n  .caption-right {\n    text-align: right;\n  }\n</style>\n\n<script>\ndocument.addEventListener('DOMContentLoaded', function() {\n  const slider = document.getElementById('imageComparisonSlider');\n  const sliderHandle = document.getElementById('sliderHandle');\n  const imageWrapper = document.getElementById('imageWrapper');\n  const caption1 = document.getElementById('caption1');\n  const caption2 = document.getElementById('caption2');\n  let isDragging = false;\n  let currentX;\n\n  function updateSliderPosition() {\n    if (!isDragging && currentX === undefined) return;\n\n    const sliderRect = slider.getBoundingClientRect();\n    let position = (currentX - sliderRect.left) / sliderRect.width;\n    position = Math.max(0, Math.min(position, 1));\n\n    sliderHandle.style.left = `${position * 100}%`;\n    imageWrapper.style.clipPath = `inset(0 ${100 - position * 100}% 0 0)`;\n\n    // Update caption opacity\n    if (caption1 && caption2) {\n      const minOpacity = 0.20;\n      const maxOpacity = 1;\n      const opacityRange = maxOpacity - minOpacity;\n\n      let opacity1 = minOpacity + opacityRange * (1 - position);\n      let opacity2 = minOpacity + opacityRange * position;\n\n      caption1.style.opacity = opacity1;\n      caption2.style.opacity = opacity2;\n    }\n\n    requestAnimationFrame(updateSliderPosition);\n  }\n\n  function startDragging(e) {\n    isDragging = true;\n    currentX = e.clientX || e.touches[0].clientX;\n    requestAnimationFrame(updateSliderPosition);\n  }\n\n  function stopDragging() {\n    isDragging = false;\n    currentX = undefined;\n  }\n\n  function onMove(e) {\n    if (!isDragging) return;\n    currentX = e.clientX || e.touches[0].clientX;\n  }\n\n  sliderHandle.addEventListener('mousedown', startDragging);\n  sliderHandle.addEventListener('touchstart', startDragging);\n\n  document.addEventListener('mousemove', onMove);\n  document.addEventListener('touchmove', onMove, { passive: false });\n\n  document.addEventListener('mouseup', stopDragging);\n  document.addEventListener('touchend', stopDragging);\n\n  slider.addEventListener('click', function(e) {\n    currentX = e.clientX;\n    requestAnimationFrame(updateSliderPosition);\n  });\n\n  // Initialize slider position\n  currentX = slider.getBoundingClientRect().left + slider.offsetWidth / 2;\n  requestAnimationFrame(updateSliderPosition);\n});\n</script>\n\n<p>Apple has honed in their <code class=\"language-plaintext highlighter-rouge\">config.toml</code> to supercharge iOS development. Notes on Liquid Glass, call outs for Foundation Models — the list goes on. Though Apple blasts the doors off of their “big” stuff at W.W.D.C., you’d be crazy to think they aren’t paying attention. How we develop software is changing, and internally, it’s clear they are humming along with it. The fact that Xcode 26.3 exists, <em>right now</em>, is proof. They didn’t just cut a new branch once Codex’s macOS app shipped.</p>\n\n<p>A few thoughts on the core pillars:</p>\n\n<div class=\"not-prose mt-8 -mb-4\">\n  <h3 class=\"bg-gradient-to-l from-blue-500 to-fuchsia-500 bg-clip-text text-transparent text-2xl font-bold leading-relaxed\">\n    Skill files\n  </h3>\n</div>\n<p>In Apple’s <a href=\"https://developer.apple.com/documentation/xcode/setting-up-coding-intelligence\">documentation</a>, they hint that each agentic option is customizable. But to what end, it’s not entirely clear:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/agentic_docs.jpeg\" role=\"presentation\" srcset=\"../assets/images/agentic_docs.jpeg\" alt=\"Month of marketing gameplan.\" /></p>\n\n<p>However, opening that up reveals a lot:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/agentic_fp.jpeg\" role=\"presentation\" srcset=\"../assets/images/agentic_fp.jpeg\" alt=\"Month of marketing gameplan.\" /></p>\n\n<p>A skills folder! I simply copied what I had in my existing <code class=\"language-plaintext highlighter-rouge\">~/.codex/skills</code> over there, and I could confirm that Xcode’s Codex could now see them:</p>\n\n<p><img class=\"lozad mx-auto max-w-full h-auto shadow-2xl rounded-lg h-18\" data-src=\"../assets/images/agentic_skills.jpeg\" role=\"presentation\" srcset=\"../assets/images/agentic_skills.jpeg\" alt=\"Month of marketing gameplan.\" /></p>\n\n<div class=\"not-prose mt-8 -mb-4\">\n  <h3 class=\"bg-gradient-to-l from-blue-500 to-fuchsia-500 bg-clip-text text-transparent text-2xl font-bold leading-relaxed\">\n    MCPs\n  </h3>\n</div>\n<p>Since we know where the <code class=\"language-plaintext highlighter-rouge\">config.toml</code> is at, moving over MCPs should not be a problem, either. Just add them in Apple’s <code class=\"language-plaintext highlighter-rouge\">config.toml</code> and you’ll be good to go. What I’m not entirely sure about is how to kick off authentication for some MCPs that may require it. For example, to get Supabase working in Codex, I’d run <code class=\"language-plaintext highlighter-rouge\">codex mcp login supabase</code> — but it needs to be ran out of session. But, there is no “out of session” in this case. It may just work, but I’ve not tried it yet.</p>\n\n<div class=\"not-prose mt-8 -mb-4\">\n  <h3 class=\"bg-gradient-to-l from-blue-500 to-fuchsia-500 bg-clip-text text-transparent text-2xl font-bold leading-relaxed\">\n    agents.md\n  </h3>\n</div>\n<p>There’s nothing to say here, it just works.</p>\n\n<h3 id=\"odds-and-ends\">Odds and ends</h3>\n\n<p>So, how is the actual experience? Well, pretty nice! This is such a tiny thing, but in Terminal — removing a chunk of text <em>sucks</em>. I’m sure there is some keyboard shortcut I’m missing, or some other app I could use like iTerm or what have you, but not being able to use <code class=\"language-plaintext highlighter-rouge\">Command+A</code> and then delete a text selection hurts. In Xcode, that’s easily done because the input is no longer running through Terminal, it’s just an AppKit text entry control.</p>\n\n<p>Oh, and it’s pretty! Apple has leaned into a bit of a bolder text for prompt creation, and the colorful “ribbon”, synonymous with Apple Intelligence, is always a joy to look at. It’s also so beautifully native. Codex’s app, while packed full of goodies, just feels…a little <em>ugh</em>, ya know? This surprised me, since their flagship ChatGPT is native and feels incredible to use (complete with Liquid Glass on Tahoe).</p>\n\n<p>But there are no free lunches in life. Another Codex installation, another agent to use, another spot you have to maintain skills and MCPs. Surely, the developers behind these agentic tool chains will adopt an open standard so we don’t have to worry about this. In fact, this has already been proposed by OpenAI developers for skills at least (I lost the tweet, but it’s out there).</p>\n\n<p>We don’t know which model will “win”, or if one <em>ever</em> will. Personally, I find the competition necessary and good for their target market, developers. I personally hope none of them win and keep pushing each other to be better. But, open standards to control all of the core pillars would be welcome. When I update one skill, I now update it in three different places.</p>\n\n<h3 id=\"wrapping-up\">Wrapping up</h3>\n\n<p>This is a fantastic start for Xcode. If you’re late to the Claude Code or Codex scene, this is a wonderful place to start. There’s simply no going back once you learn how to use these tools. Ideas that you wanted to hack on become doable, those dusty side project folders come alive a bit more, and you get ideas out of your head much faster. These are all good things.</p>\n\n<p>Plus, it makes you wonder what Apple will have for us at this year’s W.W.D.C. — this release is the kind of thing you typically see there. Maybe they felt they had to respond earlier? Maybe it was just ready to go? Maybe they have #EvenMoreCoolThings coming? I dunno, but I’m eager to see.</p>\n\n<p>It’s all moving quickly. All the way back in 2020, <a href=\"https://nshipster.com/as-we-may-code/\">Mattt sort of saw some of this coming</a>. It’s fun to read that post back, and see how so much of it is happening today. What a time to build!</p>\n\n<p>Until next time ✌️</p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\">\n      <p>Kind of odd that it’s Electron though, yeah? The ChatGPT flagship app is native, and it feels fantastic in comparison. <a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;</a></p>\n    </li>\n  </ol>\n</div>",
            "summary": "I was filled with whimsy watching OpenAI announce their Codex app1 not even two days ago. But life comes at you fast. The very next day, Xcode 26.3 dropped with support for agentic coding. Kind of odd that it’s Electron though, yeah? The ChatGPT flagship app is native, and it feels fantastic in comparison. &#8617;",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-02-04T00:00:00-06:00",
            "date_modified": "2026-02-04T00:00:00-06:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["A.I."]},{
            "id": "https://swiftjectivec.com/Best-in-Class-iOS-App-Book-Series-Price-Update",
            "url": "https://swiftjectivec.com/Best-in-Class-iOS-App-Book-Series-Price-Update/",
            "title": "Pay What You Want for The Best-in-Class iOS App Book Series",
            "content_html": "<p>First, let me get straight to it:</p>\n\n<p>The <a href=\"https://bestinclassiosapp.com\">Best-in-Class iOS App Book Series</a> is now <em>pay what you want</em>! Pick it up for a minimum of $10 to…whatever you want. Live now!</p>\n\n<h3 id=\"so-why\">So, Why?</h3>\n\n<p>I debuted this book series many years ago now, back in <a href=\"https://www.swiftjectivec.com/Introducing-The-Best-in-Class-Book/\">2021</a>!</p>\n\n<div class=\"jekyll-twitter-plugin\"><blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">🚀A Best-in-Class App: The Book 🚀<br /><br />It&#39;s happening, I&#39;m making this now! <br /><br />✅ In-depth book covering accessibility, core iOS tech, design, user experience and more.<br />✅ A companion app <br />✅ Bite sized screencasts<br /><br />Join the mailing list to follow along: <a href=\"https://t.co/Dc9AcfyUSL\">https://t.co/Dc9AcfyUSL</a> <a href=\"https://t.co/S8sm1zPnNg\">pic.twitter.com/S8sm1zPnNg</a></p>&mdash; Jordan Morgan (@JordanMorgan10) <a href=\"https://twitter.com/JordanMorgan10/status/1361707249366884354?ref_src=twsrc%5Etfw\">February 16, 2021</a></blockquote>\n<script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n</div>\n\n<p>I had just sold my first somewhat successful app, and figured I’d set out to do what I always wanted to do: write a book series of all that I knew about making iOS apps. The craft, the APIs, the design, the “don’t sleep on this little tweak” kind of stuff.</p>\n\n<p>And, so, I did — though it was a bit grueling.</p>\n\n<p>It took over two and a half years, and I released updates every two weeks during that time. But, like I would imagine those who finished a PhD or something, I was (and still am) extremely proud of the effort even though the effort basically swallowed me whole. I wrote over a thousand pages, hundreds of code samples, just as many image assets, kept the mailing list informed of progress, the whole gig. And since then, I’ve kept it up to date with free content drops.</p>\n\n<p>What I couldn’t have imagined, at the time, was where we are today. Right now. The way we learn and do things, and most importantly — develop software, is changing at an unprecedented pace. AI and LLMs are changing our industry in real time. While there is certainly a place for books, YouTube tutorials, and similar content (I don’t think anybody wants those to go away) - I think the desire for a giant reference like mine is reducing a bit.</p>\n\n<p>And that’s okay, but I also want to be realistic about things. And so, with updates slowing, I want to make it’s accessible to anyone who might want it.</p>\n\n<h3 id=\"whats-next\">What’s Next?</h3>\n\n<p>I’ve also had several ideas floating around on what I could do with this content. With five, giant books full of iOS wisdom, plugging it into an LLM, custom GPT, maybe even an MCP, or putting it online digitally to highlight things, even edit it, etc — that could be fun. By far, the largest pain point is updating this thing. It takes hours to do for several reasons. An online-first home for it, with the option to download it still as it is today, would make the barrier to entry for updates much, <em>much</em> more doable for me.</p>\n\n<p>I’m not really sure what I’ll do with it, but with over 100 updates since 2021, I’ve given this project a lot of me. I’m proud of it, and I’m also happy that whoever wanted it but couldn’t afford it, can do so now.</p>\n\n<p>Until next time ✌️</p>",
            "summary": "First, let me get straight to it:",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-01-28T00:00:00-06:00",
            "date_modified": "2026-01-28T00:00:00-06:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["The Indie Dev Diaries"]},{
            "id": "https://swiftjectivec.com/The-Shift-Using-AI-As-A-Developer-Advocate-And-Engineer",
            "url": "https://swiftjectivec.com/The-Shift-Using-AI-As-A-Developer-Advocate-And-Engineer/",
            "title": "The Shift",
            "content_html": "<p>It’s 2026 (in case you didn’t notice). Where have my traditional “Here’s what I did last year, here’s what I wanna do this year!” posts gone? I was able to achieve nearly all my goals in 2025 (the first time that’s happened), and I just sold <a href=\"https://www.swiftjectivec.com/introducing-elite-soccer-club/\">Elite Soccer Club</a> to a friend, and I’ve got huge plans for 2026!</p>\n\n<p>Why haven’t I written about any of it yet?</p>\n\n<p>Well, because as a once ancient tweet once said, <em>everything just happens so much.</em> And in our industry, I don’t think I’ve ever witnessed so much happening.</p>\n\n<p>I’ve known AI was helpful and it’s been a daily driver for me for some time now (ever the early adopter). But after seeing good ol’ <a href=\"https://x.com/steipete\">Steipete</a> and <a href=\"https://x.com/Dimillian\">Thomas</a> share more and more about their adventures, I started to dig in some more.</p>\n\n<p>Skills, rules, plugins, MCPs, different models — I <em>went in</em>. And, coming out the other side, I’m not entirely certain what to think anymore. Excitement? Nervous? Pumped? All of it?</p>\n\n<p>It’s all different now, but I do know that if you were already an engineer with experience before this AI boom, there has never been a better time in human history to build stuff.</p>\n\n<p><strong>If you knew a <em>little</em> about a tech stack? Well, now you know a lot.</strong></p>\n\n<p>I’ve been wondering what I am now with AI specifically. How would I describe myself? I don’t fancy myself as a vibe coder, I think we’ve attached a pejorative mindset to that term — one that won’t be shaken anytime soon. I think “Agentic Engineering” fits? Someone who knows what these things can do, and equally as important — how they could bring your house down if you don’t pay attention.</p>\n\n<p>At work, I’ve been committing more code to our monorepo, our marketing site, cruising through Next.JS and Astro codebases, all the while doing a bunch of other stuff. And, it’s simply because…now I can.</p>\n\n<p>Not even a year ago, Xcode stayed open while I cherry picked work over to chatGPT. Now, I have four terminals open - managing my little LLM minions to do my bidding. Sometimes, it feels like I code review for a living. But, I’m enjoying it?</p>\n\n<p>My role has even been…impacted…if that’s the best word?, by AI. Developers are watching less YouTube tutorials and are relying on MCP servers for docs. The world is absolutely changing, and it is mind-boggling to be in it while it’s happening.</p>\n\n<h3 id=\"wrapping-up\">Wrapping Up</h3>\n<p>When your industry shifts seemingly overnight, where does that put you? You either change with it, or open a coffee bar (Dude, I would <em>love</em> to open a coffee bar by the way).</p>\n\n<p>I think we’re all a bit on edge, to some degree. The thought that, eventually, anybody will be able to make an app is exciting and a bit scary.</p>\n\n<p>The barrier used to be building, and that barrier is diminishing. That means, logically, that the best idea, and its execution, its design and UX, how well it solves the problem - those will win more and more. That’s kinda, sorta, mostly true today, but the build aspect is still there right now. You could have the best taste, ideas on superior execution - but you might not be able to build the thing right now. That will change.</p>\n\n<p>As such, where does that leave us?</p>\n\n<p>I can’t say, but I do know that this is true, right now:</p>\n\n<ul>\n  <li>If you know how to code, then you are an absolute machine now. You can find the dumb stuff AI does, and you don’t treat it as a loose cannon. You guide it with tact, thinking, poise and a plan. It’s a force multiplier, not fertile ground for bugs.</li>\n  <li>If you can design <em>and</em> code? Well, the world is yours…for now. All of these things will become more accessible in due time.</li>\n</ul>\n\n<p>In short? Go build, and do it now! We’ve got a major head start.</p>\n\n<p>Until next time ✌️</p>",
            "summary": "It’s 2026 (in case you didn’t notice). Where have my traditional “Here’s what I did last year, here’s what I wanna do this year!” posts gone? I was able to achieve nearly all my goals in 2025 (the first time that’s happened), and I just sold Elite Soccer Club to a friend, and I’ve got huge plans for 2026!",
            "image": "https://swiftjectivec.com/assets/images/logo.png",
            "date_published": "2026-01-18T00:00:00-06:00",
            "date_modified": "2026-01-18T00:00:00-06:00",
            "author": {
              "name": "Jordan Morgan"},
            "tags": ["A.I."]}]
}