<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Anton’s Substack]]></title><description><![CDATA[My personal Substack (and that's true!) about iOS Development]]></description><link>https://antongubarenko.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!mzA2!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1eb672de-f6cd-47a2-98b2-6de3f5be6ffe_2316x3088.jpeg</url><title>Anton’s Substack</title><link>https://antongubarenko.substack.com</link></image><generator>Substack</generator><lastBuildDate>Sun, 19 Jul 2026 01:30:28 GMT</lastBuildDate><atom:link href="https://antongubarenko.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Anton Gubarenko]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[antongubarenko@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[antongubarenko@substack.com]]></itunes:email><itunes:name><![CDATA[Anton Gubarenko]]></itunes:name></itunes:owner><itunes:author><![CDATA[Anton Gubarenko]]></itunes:author><googleplay:owner><![CDATA[antongubarenko@substack.com]]></googleplay:owner><googleplay:email><![CDATA[antongubarenko@substack.com]]></googleplay:email><googleplay:author><![CDATA[Anton Gubarenko]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Swift Bits: My Top Xcode CI Environment Variables]]></title><description><![CDATA[Popular CI variables]]></description><link>https://antongubarenko.substack.com/p/swift-bits-my-top-xcode-ci-environment</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/swift-bits-my-top-xcode-ci-environment</guid><pubDate>Tue, 14 Jul 2026 06:18:52 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c4882cb3-152c-4b1f-bc4d-cd3780baf6c5_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Xcode Cloud scripts fail in the least cinematic way possible: one tiny assumption, one missing context value, and suddenly CI behaves nothing like your local machine &#128517;</p><p>That is where Apple&#8217;s environment variable reference becomes more useful than it looks. It is not documentation you read for fun. It is documentation you need when your custom build script has to understand what workflow is running, what build action is happening, which app target is involved, or what commit produced the artifact.</p><p>And this connects directly with custom build scripts. Xcode Cloud supports scripts inside a <code>ci_scripts</code> directory next to your project or workspace, which is usually where teams hide the real CI glue: dependency setup, generated files, dSYM uploads, release metadata, logging, and workflow-specific checks.</p><p>Hardcoded CI scripts age badly. Context-aware scripts survive longer.</p><p>I&#8217;m sharing some of the popular ones that are actually handy when you need your build scripts to stop guessing and start reacting to the real workflow &#128736;&#65039;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BFju!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BFju!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png 424w, https://substackcdn.com/image/fetch/$s_!BFju!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png 848w, https://substackcdn.com/image/fetch/$s_!BFju!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png 1272w, https://substackcdn.com/image/fetch/$s_!BFju!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BFju!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png" width="1200" height="2113" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2113,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:205937,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://antongubarenko.substack.com/i/201284578?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BFju!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png 424w, https://substackcdn.com/image/fetch/$s_!BFju!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png 848w, https://substackcdn.com/image/fetch/$s_!BFju!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png 1272w, https://substackcdn.com/image/fetch/$s_!BFju!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5365f5-ef28-4e34-8110-33666e2946fb_1200x2113.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>References</h2><ul><li><p><a href="https://developer.apple.com/documentation/xcode/writing-custom-build-scripts">Apple Docs: Writing custom build scripts</a></p></li><li><p><a href="https://developer.apple.com/documentation/xcode/environment-variable-reference">Apple Docs: Environment variable reference</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[iOS 27: Scene Close Confirmation]]></title><description><![CDATA[Prevent and handle scene close]]></description><link>https://antongubarenko.substack.com/p/ios-27-scene-close-confirmation</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/ios-27-scene-close-confirmation</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Mon, 13 Jul 2026 09:38:15 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/be02439c-a778-4410-acf1-ea87cd8f2447_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let&#8217;s continue our iOS 27 WWDC explorations.</p><blockquote><p>This feature is still in beta and might change before the final release.</p></blockquote><p>Apple added a new UIKit API called <code>UISceneClosureConfirmation</code>, and <code>UIWindowScene</code> now exposes a <code>closureConfirmation </code>property for assigning it.</p><p>Even if your app is written in SwiftUI, scene management still goes through UIKit under the hood. That is why this API matters for SwiftUI apps too: the UI state may live in SwiftUI, but the close confirmation is attached to the underlying <code>UIWindowScene</code>.</p><p>When a scene is about to close, some apps need a chance to confirm that action first. The most obvious example is unsaved work. A SwiftUI text editor, document-style flow, or form-heavy screen may need to warn the user before the window disappears.</p><p>That is where this API becomes interesting. Instead of treating scene closure as an event you only react to after the fact, UIKit gives SwiftUI apps a lower-level scene hook for explicit close confirmation.</p><div><hr></div><h2>What It Is</h2><p><code>UISceneClosureConfirmation</code> is a UIKit scene API, but it can be useful in SwiftUI apps that support multiple windows.</p><p>The important part is the boundary: SwiftUI owns the visible state and editing flow, while <code>UIWindowScene</code> owns the close-confirmation hook.</p><p>Conceptually, it fits a very familiar UX problem:</p><ul><li><p>the user closes a scene</p></li><li><p>the SwiftUI view still has unfinished or unsaved state</p></li><li><p>the app needs to confirm whether closing should continue</p></li></ul><p>That is especially relevant in multi-window environments, document-style SwiftUI apps, and any workflow where closing a scene can throw away user progress.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GUOh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GUOh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png 424w, https://substackcdn.com/image/fetch/$s_!GUOh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png 848w, https://substackcdn.com/image/fetch/$s_!GUOh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png 1272w, https://substackcdn.com/image/fetch/$s_!GUOh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GUOh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png" width="1456" height="2095" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2095,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:795719,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://antongubarenko.substack.com/i/204062962?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GUOh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png 424w, https://substackcdn.com/image/fetch/$s_!GUOh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png 848w, https://substackcdn.com/image/fetch/$s_!GUOh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png 1272w, https://substackcdn.com/image/fetch/$s_!GUOh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84d1e11-e774-49f1-ae7b-9f131a42e040_1640x2360.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Xcode Beta 3 - Simulator Window Confirmation</figcaption></figure></div><div><hr></div><h2>Why It Matters</h2><p>In SwiftUI apps, this is easy to miss because most of the UI is described in views and state. But the close action itself still belongs to the scene.</p><p>Without a dedicated scene-close hook, teams often end up mixing SwiftUI state, UIKit lifecycle callbacks, and custom coordination around window state.</p><p>A dedicated close-confirmation API is better because it makes the intent explicit.</p><p>Instead of saying:</p><p>&#8220;Maybe this scene is disappearing, let&#8217;s try to intercept it.&#8221;</p><p>you can say:</p><p>&#8220;This scene may be closed, and here is how the app wants to confirm that.&#8221;</p><p>That is cleaner both architecturally and from a UX point of view.</p><div><hr></div><h2>Good Use Cases</h2><p>This API makes the most sense when closing a scene could lose meaningful user work.</p><p>Examples:</p><ul><li><p>SwiftUI text editors with unsaved changes</p></li><li><p>drawing or note-taking apps</p></li><li><p>multi-step forms</p></li><li><p>draft creation flows</p></li><li><p>SwiftUI document-style workflows</p></li><li><p>window-specific editing contexts on iPad</p></li></ul><p>If closing the scene is harmless, then confirmation is usually unnecessary. But if closing it can silently discard progress, confirmation becomes part of responsible UX.</p><div><hr></div><h2>Enable Multiple Scenes First</h2><p>To test scene close confirmation properly, make sure the app supports multiple scenes.</p><p>In <code>Info.plist</code>, enable multiple scenes under the application scene manifest. In Xcode this is usually the <code>UIApplicationSceneManifest</code> configuration with multiple scene support enabled.</p><p>Without this setup, it is easy to test only the main app window and miss the actual multiwindow behavior where scene closure becomes more visible.</p><div><hr></div><h2>Example: SwiftUI Window Close Confirmation</h2><p>In the sample project, the editable text belongs to a SwiftUI model. The close confirmation is still configured through <code>UIWindowScene</code>, because this is where the system-level scene close behavior lives.</p><p>This is not a pure SwiftUI modifier. It is a SwiftUI implementation that reaches into the underlying <code>UIWindowScene</code> to configure close behavior.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;swift&quot;,&quot;nodeId&quot;:&quot;7df9a549-2772-42f1-a826-ea1700d27c15&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-swift">let closeAction = UIAlertAction(title: "Close Window", style: .destructive) { _ in
    Task { @MainActor in
        destroyWindowScene(windowScene)
    }
}

let cancelAction = UIAlertAction(
    title: "Keep Editing",
    style: .cancel,
    handler: nil
)

let saveAction = UIAlertAction(title: "Save Text And Close", style: .default) { _ in
    Task { @MainActor in
        model.notesText = "Saved before closing."
        destroyWindowScene(windowScene)
    }
}

windowScene.closureConfirmation = UISceneClosureConfirmation(
    title: "Close This Text Window?",
    message: "This scene has its own text view state. Choose whether to close it or keep editing.",
    actions: [closeAction, cancelAction, saveAction]
)</code></pre></div><p>Full sample is available here: <a href="https://gist.github.com/lanserxt/30813af528d08cfbe9f7c67217b9090d">UISceneClosureConfirmation demo Gist</a></p><p>One important detail is that <code>UIWindowScene</code> has a <code>closureConfirmation</code> property, so the confirmation object is assigned directly to the scene.</p><p>The SwiftUI part owns the model state. The UIKit scene part owns the close confirmation.</p><p>The important part here is the shape of the flow:</p><ul><li><p>create the close-related actions</p></li><li><p>read or update SwiftUI-owned state</p></li><li><p>decide whether the user should keep editing, save, or close</p></li><li><p>assign the confirmation object to the window scene</p></li></ul><blockquote><p>The snippet above is meant to show the architecture and usage pattern. The concrete detail you can rely on is that <code>UIWindowScene</code> exposes a <code>closureConfirmation</code> property for assigning a <code>UISceneClosureConfirmation</code> instance.</p></blockquote><div><hr></div><h2>Design Advice</h2><p>A few things are worth keeping in mind.</p><h3>1. Confirm Only When It Matters</h3><p>Do not show a close confirmation just because you can. If there is no risk of data loss, the confirmation becomes friction.</p><h3>2. Tie It To Real Dirty State</h3><p>The decision should come from meaningful user changes, not from &#8220;the screen was opened&#8221; or &#8220;some state exists.&#8221;</p><h3>3. Keep The Dialog Clear</h3><p>The user should immediately understand what is at risk:</p><ul><li><p>unsaved text</p></li><li><p>unfinished form input</p></li><li><p>document edits</p></li><li><p>discarded draft changes</p></li></ul><h3>4. Avoid Confirmation Loops</h3><p>If save itself can fail or open another modal path, keep that flow predictable. The user should always know whether they are still closing or are back in editing mode.</p><div><hr></div><h2>Why This Feels Like A Good Addition</h2><p>SwiftUI apps can still run into scene-level problems, especially on iPad and in multiwindow workflows. Even when most of the app is SwiftUI, the window and scene lifecycle are still UIKit concepts.</p><p>A dedicated scene close confirmation API makes the intent much more visible in code:</p><ul><li><p>this scene can close</p></li><li><p>this app may need to block closing</p></li><li><p>this is how the user decides</p></li></ul><p>That is a better model than scattering close-protection logic across unrelated lifecycle callbacks.</p><div><hr></div><h2>Final Thoughts</h2><p><code>UISceneClosureConfirmation</code> looks like a small API, but it addresses a very real UX problem.</p><p>Closing a scene is not always harmless. In SwiftUI apps, it can still mean losing edits, abandoning a draft, or discarding user effort. A dedicated confirmation model gives the app a cleaner and more explicit way to handle that.</p><p>For SwiftUI developers, the main takeaway is not that this becomes a new SwiftUI modifier. It is that some window-level behavior still belongs to UIKit, and <code>UIWindowScene.closureConfirmation</code> gives you a clear place to configure it.</p><div><hr></div><h2>References</h2><ul><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/uikit/uisceneclosureconfirmation">UISceneClosureConfirmation</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/uikit/uiwindowscene/closureconfirmation">UIWindowScene.closureConfirmation</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/uikit/uiwindowscene">UIWindowScene</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/uikit/app_and_environment/scenes/supporting_multiple_windows_on_ipad">Supporting multiple windows on iPad</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[iOS27: CADisplayLink for UIWindowScene]]></title><description><![CDATA[Track refresh of an each Scene]]></description><link>https://antongubarenko.substack.com/p/ios27-cadisplaylink-for-uiwindowscene</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/ios27-cadisplaylink-for-uiwindowscene</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Tue, 07 Jul 2026 08:03:55 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/16cd3b45-a9ee-484c-b3a9-68aad50e08da_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Scheduled timers often come in handy. They are useful when you need to show a countdown, refresh some value every second, or make a periodic poll request.</p><p>But <code>CADisplayLink</code> has always stood on higher ground.</p><p>That is because <code>Timer</code> is time-based, while <code>CADisplayLink</code> is frame-based. A timer fires according to a run loop schedule. A display link fires in sync with the display refresh cycle. When the work you are doing is visual, that difference matters a lot.</p><blockquote><p>During years I&#8217;ve faced <code>CADisplayLink</code> only a few times and it&#8217;s time to learn about it!</p></blockquote><p>Another useful way to frame it is in Hz. A standard 60 Hz display can present up to 60 frames per second, while higher-refresh displays can go beyond that. <code>CADisplayLink</code> follows that rendering cadence, which is exactly why it feels more natural for animation and frame-driven UI work than a regular timer.</p><div><hr></div><h2>What It Is</h2><p><code>CADisplayLink</code> is a QuartzCore object that lets your code run in step with screen updates.</p><p>That makes it a natural fit for:</p><ul><li><p>smooth custom animations</p></li><li><p>progress that needs to track frames precisely</p></li><li><p>rendering loops</p></li><li><p>physics-like visual updates</p></li><li><p>UI that should advance only when a new frame is about to be displayed</p></li></ul><p>This is the key mental model: <code>CADisplayLink</code> is not just &#8220;a timer that fires fast.&#8221; It is display-synchronized work.</p><div><hr></div><h2>Why It Differs From Timer</h2><p>A <code>Timer</code> is about time intervals.</p><p>A <code>CADisplayLink</code> is about frame boundaries.</p><p>That one difference changes how they behave in practice.</p><h3>Timer</h3><p>Use <code>Timer</code> when you care about elapsed time more than visual smoothness.</p><p>Examples:</p><ul><li><p>a countdown label</p></li><li><p>a polling request every few seconds</p></li><li><p>refreshing cached data periodically</p></li><li><p>lightweight background scheduling tied to a run loop</p></li></ul><h3>CADisplayLink</h3><p>Use <code>CADisplayLink</code> when your update is visually tied to the screen.</p><p>Examples:</p><ul><li><p>moving or redrawing something every frame</p></li><li><p>tracking animation progress manually</p></li><li><p>synchronizing custom rendering with the display</p></li><li><p>driving a game-like loop in UIKit</p></li></ul><p>If you try to drive visual motion with a regular timer, it can work, but it is usually less precise and less naturally aligned with what the display is doing.</p><div><hr></div><h2>Basic Setup</h2><p>A common setup looks like this:</p><pre><code><code>import QuartzCore
import UIKit

final class DisplayLinkViewController: UIViewController {
    private var displayLink: CADisplayLink?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startDisplayLink()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        stopDisplayLink()
    }

    private func startDisplayLink() {
        let link = CADisplayLink(target: self, selector: #selector(step))
        link.add(to: .main, forMode: .common)
        displayLink = link
    }

    private func stopDisplayLink() {
        displayLink?.invalidate()
        displayLink = nil
    }

    @objc private func step(_ link: CADisplayLink) {
        print("Frame timestamp: \(link.timestamp)")
    }
}
</code></code></pre><p>This already shows one important difference from <code>Timer</code>: you usually treat display link lifetime much more carefully, because it is easy to keep doing work every frame when you no longer need to.</p><div><hr></div><h2>SwiftUI Example</h2><p>Even in SwiftUI, <code>CADisplayLink</code> can still make sense when you need frame-driven updates rather than interval-based ones.</p><p>One practical way is to keep the display link inside a small helper object and push the visible value back into SwiftUI state.</p><pre><code><code>import SwiftUI
import QuartzCore

final class DisplayLinkDriver {
    var onFrame: ((CFTimeInterval) -&gt; Void)?
    private var displayLink: CADisplayLink?

    func start() {
        guard displayLink == nil else { return }

        let link = CADisplayLink(target: self, selector: #selector(step))
        link.add(to: .main, forMode: .common)
        displayLink = link
    }

    func stop() {
        displayLink?.invalidate()
        displayLink = nil
    }

    @objc private func step(_ link: CADisplayLink) {
        onFrame?(link.targetTimestamp)
    }

    deinit {
        stop()
    }
}

struct DisplayLinkDemoView: View {
    @State private var progress: CGFloat = 0
    @State private var direction: CGFloat = 1
    private let driver = DisplayLinkDriver()

    var body: some View {
        VStack(spacing: 24) {
            Text("Frame-driven progress")

            Capsule()
                .fill(.gray.opacity(0.2))
                .frame(height: 12)
                .overlay(alignment: .leading) {
                    Capsule()
                        .fill(.blue)
                        .frame(width: max(12, progress * 240), height: 12)
                }
                .frame(width: 240)
        }
        .onAppear {
            driver.onFrame = { _ in
                let next = progress + (0.01 * direction)

                if next &gt;= 1 {
                    progress = 1
                    direction = -1
                } else if next &lt;= 0 {
                    progress = 0
                    direction = 1
                } else {
                    progress = next
                }
            }

            driver.start()
        }
        .onDisappear {
            driver.stop()
        }
    }
}
</code></code></pre><p>The idea is the same as in UIKit: use <code>CADisplayLink</code> when the update should move with frames, not just with elapsed time.</p><div><hr></div><h2>Important Values</h2><p>A few <code>CADisplayLink</code> properties are especially useful.</p><h3>timestamp</h3><p>This is the timestamp of the last displayed frame.</p><h3>targetTimestamp</h3><p>This gives you the timestamp for the next frame. It is often more useful when calculating frame progress.</p><h3>duration</h3><p>This is the interval between screen refreshes as reported by the link.</p><h3>preferredFrameRateRange</h3><p>This gives you more control over the cadence you want, instead of always blindly running at the highest possible rate.</p><p>That matters more now, because &#8220;every frame&#8221; is not always the same thing across devices and refresh rates. On a 60 Hz display, one frame is typically about 16.67 ms. On a 120 Hz display, it is about 8.33 ms. That is a meaningful difference when you are calculating motion, progress, or per-frame work.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GlPx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GlPx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png 424w, https://substackcdn.com/image/fetch/$s_!GlPx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png 848w, https://substackcdn.com/image/fetch/$s_!GlPx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png 1272w, https://substackcdn.com/image/fetch/$s_!GlPx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GlPx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png" width="1121" height="1403" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/186e0932-8147-4999-adeb-d5f093564257_1121x1403.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1403,&quot;width&quot;:1121,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1282677,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://antongubarenko.substack.com/i/204063060?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GlPx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png 424w, https://substackcdn.com/image/fetch/$s_!GlPx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png 848w, https://substackcdn.com/image/fetch/$s_!GlPx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png 1272w, https://substackcdn.com/image/fetch/$s_!GlPx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F186e0932-8147-4999-adeb-d5f093564257_1121x1403.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Refresh based on Hz</figcaption></figure></div><div><hr></div><h2>Common Caveats</h2><p><code>CADisplayLink</code> is powerful, but it is also easy to misuse.</p><h3>1. It Is Not A General Replacement For Timer</h3><p>If you only need to refresh a countdown every second, <code>Timer</code> is usually the simpler and cheaper tool.</p><p>Using <code>CADisplayLink</code> for that would mean waking up every frame just to update something that only changes once a second.</p><h3>2. It Can Waste Work Fast</h3><p>A display link can fire very often. If your callback is heavy, you will feel it quickly in dropped frames, CPU usage, or battery cost.</p><h3>3. You Must Manage Lifetime</h3><p>Invalidate it when you are done.</p><p>Forgetting to stop a display link is one of the easiest ways to keep a controller alive longer than expected or keep doing frame work off-screen.</p><h3>4. Run Loop Mode Matters</h3><p>Adding it with <code>.common</code> is often the practical choice in UI code, because default run loop mode alone may not behave the way you expect during interactions.</p><h3>5. It Is Best For Visual Work</h3><p>This is the big one.</p><p><code>CADisplayLink</code> shines when your logic is tied to drawing or visible animation. For networking, clocks, or ordinary periodic tasks, <code>Timer</code> is often still the better fit.</p><div><hr></div><h2>A Good Comparison Example</h2><p>Here is a simple rule of thumb.</p><p>If you are building:</p><ul><li><p>a countdown to an event &#8594; use <code>Timer</code></p></li><li><p>a polling request every 30 seconds &#8594; use <code>Timer</code></p></li><li><p>a custom animation progress loop &#8594; use <code>CADisplayLink</code></p></li><li><p>a frame-by-frame canvas update &#8594; use <code>CADisplayLink</code></p></li></ul><p>That keeps the tools aligned with the kind of work they were meant to do.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_N0f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_N0f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!_N0f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!_N0f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!_N0f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_N0f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1500501,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://antongubarenko.substack.com/i/204063060?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_N0f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!_N0f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!_N0f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!_N0f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67438bf4-1e6c-4d17-925a-97aae59a6ea5_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Timer vs CADisplayLink</figcaption></figure></div><div><hr></div><h2>The New iOS 27 Direction</h2><p>The interesting part in iOS 27 is that Apple is pushing <code>CADisplayLink</code> in a more scene-aware direction.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6pDg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6pDg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png 424w, https://substackcdn.com/image/fetch/$s_!6pDg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png 848w, https://substackcdn.com/image/fetch/$s_!6pDg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png 1272w, https://substackcdn.com/image/fetch/$s_!6pDg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6pDg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png" width="1456" height="453" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:453,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:127096,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://antongubarenko.substack.com/i/204063060?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6pDg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png 424w, https://substackcdn.com/image/fetch/$s_!6pDg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png 848w, https://substackcdn.com/image/fetch/$s_!6pDg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png 1272w, https://substackcdn.com/image/fetch/$s_!6pDg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33ca07e6-5e4b-4a4d-811e-04ecb08b54c6_1928x600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><blockquote><p>It is also worth calling out that iOS 27 is still in beta, so the exact API shape and naming may still change before final release.</p></blockquote><p>That is a meaningful shift.</p><p>Until now, display link setup was usually thought about in terms of a screen or a run loop, but not as explicitly in terms of a specific window scene. With the new API direction, you can now create it in a way that is linked to a <code>UIWindowScene</code>.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;swift&quot;,&quot;nodeId&quot;:&quot;32beecb5-a884-4070-8f1f-535a0e11ddae&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-swift">import UIKit

final class DemoViewController: UIViewController {
    private var displayLink: CADisplayLink?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        if let scene = view.window?.windowScene {
            //iOS 27 Beta
            displayLink = scene.displayLink { link in
                print(link.targetTimestamp - link.timestamp)
            }
            displayLink?.add(to: .main, forMode: .common)
        }
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        displayLink?.invalidate()
        displayLink = nil
    }
}</code></pre></div><p>That is a better fit for modern UIKit apps, especially on iPad and other environments where scenes matter more.</p><p>Why does that matter?</p><p>Because visual work is often not just &#8220;device-wide.&#8221; It belongs to a particular window, a particular scene, and a particular visible UI context. As UIKit becomes more scene-oriented, display-driven work benefits from becoming scene-aware too.</p><div><hr></div><h2>Why Scene Linking Makes Sense</h2><p>A scene-linked display link fits modern app architecture better in a few ways.</p><h3>Better Ownership</h3><p>If rendering or animation belongs to one window scene, it makes sense for the display link to belong there too.</p><h3>Better Multiwindow Behavior</h3><p>On iPad or multiwindow environments, scene ownership is much clearer than treating display updates as one global concern.</p><h3>Better Mental Model</h3><p>This is probably the biggest improvement.</p><p>Instead of thinking:</p><p>&#8220;Here is a display link somewhere in the app.&#8221;</p><p>you can think:</p><p>&#8220;Here is display-synchronized work attached to this scene.&#8221;</p><p>That is simply easier to reason about.</p><div><hr></div><h2>Practical Takeaway</h2><p>You still should not reach for <code>CADisplayLink</code> automatically.</p><p>Use it when:</p><ul><li><p>the work is visual</p></li><li><p>smoothness matters</p></li><li><p>frame alignment matters</p></li><li><p>the update naturally belongs to visible rendering</p></li></ul><p>Use <code>Timer</code> when:</p><ul><li><p>the work is interval-based</p></li><li><p>exact frame boundaries do not matter</p></li><li><p>you are scheduling ordinary periodic tasks</p></li></ul><p>And if you are targeting iOS 27 and newer, the new scene-linked creation path is worth paying attention to, because it makes display-driven code feel much more aligned with UIKit&#8217;s scene model.</p><div><hr></div><h2>Final Thoughts</h2><p>Timers are useful because they are simple and practical.</p><p>But <code>CADisplayLink</code> has always been the more specialized tool for UI work that needs to move with the display itself. That is why it has always stood on higher ground.</p><p>The new scene-aware direction in iOS 27 makes that story even stronger. It suggests Apple wants frame-driven work to be modeled closer to where it actually belongs: not just on a run loop, but inside the lifetime and ownership of a scene.</p><p>That is a small API direction change, but a meaningful architectural one.</p><div><hr></div><h2>References</h2><ul><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/quartzcore/cadisplaylink">CADisplayLink</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/uikit/uiwindowscene/displaylink(action:)">UIWindowScene.displayLink(action:)</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Swift Bits: Xcode Cloud Build Number]]></title><description><![CDATA[Don't make a build number - magical number]]></description><link>https://antongubarenko.substack.com/p/swift-bits-xcode-cloud-build-number</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/swift-bits-xcode-cloud-build-number</guid><pubDate>Fri, 03 Jul 2026 09:26:25 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/78e87352-bac8-4933-a2c3-88abb962bfc1_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s always amazing how a great feature can ship with caveats and hidden, unclear logic. I know Apple likes to experiment and make developers&#8217; lives a bit more complicated, but this one is something else.</p><p>To prevent duplicate builds, Xcode Cloud uses its own internal build number variable &#128556;. Let&#8217;s change that.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z-a4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z-a4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png 424w, https://substackcdn.com/image/fetch/$s_!z-a4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png 848w, https://substackcdn.com/image/fetch/$s_!z-a4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png 1272w, https://substackcdn.com/image/fetch/$s_!z-a4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z-a4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png" width="1456" height="2502" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2502,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:302906,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://antongubarenko.substack.com/i/204825699?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!z-a4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png 424w, https://substackcdn.com/image/fetch/$s_!z-a4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png 848w, https://substackcdn.com/image/fetch/$s_!z-a4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png 1272w, https://substackcdn.com/image/fetch/$s_!z-a4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcdfabedf-aebf-4110-bf2d-68958ff6daaf_1800x3093.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Dynamic Color Init]]></title><description><![CDATA[Make the color reflect the scheme]]></description><link>https://antongubarenko.substack.com/p/dynamic-color-init</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/dynamic-color-init</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Tue, 30 Jun 2026 11:22:29 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/28f9bc60-227e-41b0-9072-1e038ee362cf_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you start a new app from scratch, the SwiftUI versus UIKit discussion is usually framed around productivity, navigation, animation, and team preference. But taking over a legacy app is a different problem.</p><p>At that point, UIKit is often already deep in the architecture. Screens may be hosted in UIKit and partially rebuilt with SwiftUI. Small pieces of the design system can become interchangeable between the two worlds. And that is where the decision becomes less theoretical: not every design-system primitive behaves equally well when it crosses the framework boundary.</p><p>For me, color is the clearest example.</p><p>Font and color may both look like simple shared design tokens, but they do not play the same role in a real product. Fonts are usually much more stable. Tying typography changes to color scheme is rarely a good default and can damage consistency. Color is different. Light and dark appearance are real runtime states, and if color does not adapt correctly, the UI breaks immediately.</p><blockquote><p>That is the practical distinction: in a mixed UIKit and SwiftUI codebase, dynamic color support is not a nice-to-have. It is the part that keeps the interface usable.</p></blockquote><div><hr></div><h2>Why Color Matters</h2><p>In a design system, both font and color are reused everywhere. But only one of them is expected to react constantly to appearance changes.</p><p>If a font token stays the same in light and dark mode, that is usually fine. In many apps, it is exactly what you want.</p><p>If a color token stays the same when the interface moves between light and dark appearance, that is often a bug.</p><p>And it becomes a very visible bug. Contrast drops, surfaces blend together, hierarchy disappears, and the interface can become uncomfortable or unreadable fast.</p><p>That is why the more useful question in a legacy mixed project is often not:</p><ul><li><p>Should this screen be SwiftUI or UIKit?</p></li></ul><p>But this:</p><ul><li><p>Does this design-system primitive adapt correctly in both?</p><div><hr></div></li></ul><h2>UIKit Dynamic Colors</h2><p>UIKit supports dynamic colors directly. Apple documents <code>UIColor(init(dynamicProvider:))</code> as an initializer that uses a block to determine the appropriate color values based on the specified traits. Apple&#8217;s color-creation docs also describe creating colors dynamically based on the currently active traits.</p><p>That means UIKit is not limited to static colors hard-coded for one appearance. You can define a color once and let it resolve differently for light and dark mode.</p><pre><code><code>import UIKit

enum DSColor {
    static let background = UIColor { traits in
        traits.userInterfaceStyle == .dark
        ? UIColor.black
        : UIColor.white
    }

    static let primaryText = UIColor { traits in
        traits.userInterfaceStyle == .dark
        ? UIColor.white
        : UIColor.black
    }
}
</code></code></pre><p>This is the right starting point for a legacy UIKit-heavy design system. If your tokens are still fixed values, the problem is usually not the framework choice. The problem is that the tokens are not appearance-aware yet.</p><blockquote><p>Keep in mind: color created like this is relying on traits at the moment of a call. It&#8217;s not dynamically changes with any traits changes!</p></blockquote><div><hr></div><h2>Foreground And Traits</h2><p>If the app returns from background and the relevant traits changed while it was away, for example the system appearance switched between light and dark, UIKit can resolve the dynamic color against the new traits. Apple&#8217;s docs frame dynamic colors around active traits, and UIKit provides explicit trait observation APIs for responding when observed traits change.</p><p>So the real trigger is not &#8220;app became active.&#8221; The real trigger is &#8220;the trait environment changed.&#8221;</p><p>In practice, that is exactly what you want to model in a design system anyway. How to achieve that?</p><div><hr></div><h2>Trait Changes In UIKit</h2><p>If you need to run your own update logic when appearance changes, UIKit now provides trait observation through <code>UITraitChangeObservable.registerForTraitChanges</code>. Apple documents it as registering a list of traits to observe and a closure to execute when one of those traits changes, and the API is available starting in iOS 17.</p><pre><code><code>import UIKit

final class ProfileViewController: UIViewController {
    private var registration: UITraitChangeRegistration?

    override func viewDidLoad() {
        super.viewDidLoad()

        registration = registerForTraitChanges([
            UITraitUserInterfaceStyle.self
        ]) { (self: Self, _) in
            self.applyColors()
        }

        // You can also observe other traits here when needed,
        // not only interface style.

        applyColors()
    }

    private func applyColors() {
        view.backgroundColor = DSColor.background
    }
}
</code></code></pre><p>This is useful when your colors are consumed indirectly, composed into custom layers, or affect logic beyond just assigning a <code>UIColor</code> to a standard UIKit property.</p><blockquote><p>We are closing 2 gaps:<br>- Correct color creation based on traits<br>- Track changes and relatively update it</p></blockquote><div><hr></div><h2>SwiftUI And Color</h2><p>SwiftUI approaches the same problem from the environment side.</p><p>Apple documents <code>EnvironmentValues.colorScheme</code> as the environment value you read to find out whether SwiftUI is currently displaying a view using <code>.light</code> or <code>.dark</code>. Apple also documents <code>Color</code> as resolving to a concrete value just before use in a given environment, which is what enables context-dependent appearance. </p><p>That means SwiftUI is already built around the assumption that appearance is environmental and reactive.</p><pre><code><code>import SwiftUI

struct DynamicColorView: View {
    @Environment(\.colorScheme) private var colorScheme

        var body: some View {
            VStack {
                Text(colorScheme == .dark ? "Dark" : "Light")
                    .font(.largeTitle)
                    .foregroundStyle(Color("title"))
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(colorScheme == .dark ? .black : .white)
        }
}
</code></code></pre><p>Gladly, now in Xcode 27 we can see both color appearances:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pJ-h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pJ-h!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png 424w, https://substackcdn.com/image/fetch/$s_!pJ-h!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png 848w, https://substackcdn.com/image/fetch/$s_!pJ-h!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png 1272w, https://substackcdn.com/image/fetch/$s_!pJ-h!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pJ-h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png" width="1392" height="874" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:874,&quot;width&quot;:1392,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:313318,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://antongubarenko.substack.com/i/203877717?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pJ-h!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png 424w, https://substackcdn.com/image/fetch/$s_!pJ-h!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png 848w, https://substackcdn.com/image/fetch/$s_!pJ-h!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png 1272w, https://substackcdn.com/image/fetch/$s_!pJ-h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e22fccd-644e-4f0a-a550-908c75654300_1392x874.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You do not usually ask SwiftUI to manually redraw for this. The environment changes, the view recalculates, and the color resolves again in the new context. Apple&#8217;s docs make that model pretty explicit. </p><p>I&#8217;ve just declared Color in Assets, and it works:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DRcH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DRcH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png 424w, https://substackcdn.com/image/fetch/$s_!DRcH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png 848w, https://substackcdn.com/image/fetch/$s_!DRcH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png 1272w, https://substackcdn.com/image/fetch/$s_!DRcH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DRcH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png" width="308" height="205.80645161290323" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:290,&quot;width&quot;:434,&quot;resizeWidth&quot;:308,&quot;bytes&quot;:56226,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://antongubarenko.substack.com/i/203877717?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DRcH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png 424w, https://substackcdn.com/image/fetch/$s_!DRcH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png 848w, https://substackcdn.com/image/fetch/$s_!DRcH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png 1272w, https://substackcdn.com/image/fetch/$s_!DRcH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08d8fcfa-ebb6-4915-b5ef-49efbcb40592_434x290.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">&#8220;title&#8221; color</figcaption></figure></div><p>Alex Agapov also highlighted that, you can mirror UIKit&#8217;s dynamic-color idea on the SwiftUI side by creating a small convenience initializer for <code>Color</code>. Instead of checking <code>colorScheme</code> directly in every view, the design system can expose a single dynamic <code>Color</code> value that resolves differently depending on the current SwiftUI environment.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;swift&quot;,&quot;nodeId&quot;:&quot;0b1cd704-b6fa-40a6-8625-5b34eb89b11a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-swift">public extension Color {
    init(light: Color, dark: Color) {
        let shapeStyle = ColorSchemeShapeStyle(light: light, dark: dark)
        self.init(shapeStyle)
    }

    private struct ColorSchemeShapeStyle: ShapeStyle, Hashable {
        let light: Color
        let dark: Color

        func resolve(in environment: EnvironmentValues) -&gt; Color.Resolved {
            switch environment.colorScheme {
            case .dark:
                dark.resolve(in: environment)

            case .light:
                light.resolve(in: environment)

            @unknown default:
                light.resolve(in: environment)
            }
        }
    }
}</code></pre></div><p>With this approach, SwiftUI usage becomes closer to UIKit dynamic colors:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;327e9238-d5e2-483e-9e1b-1bb7bf51b011&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">extension Color {
    static let dsBackground = Color(light: .white, dark: .black)
    static let dsPrimaryText = Color(light: .black, dark: .white)
}</code></pre></div><p>The important part is that the color is still resolved through SwiftUI&#8217;s environment. The view does not need to manually inspect <code>colorScheme</code>, and the design-system token remains dynamic instead of becoming a fixed light or dark value too early.</p><div><hr></div><h2>Legacy Project Reality</h2><p>This is where the &#8220;SwiftUI or UIKit?&#8221; question gets reframed.</p><p>In a legacy UIKit-heavy codebase, choosing UIKit for a screen is not automatically a problem. Choosing SwiftUI for a new piece is not automatically a problem either.</p><p>The real risk is pretending the design-system layer is neutral when it is not.</p><p>Some primitives cross the boundary cleanly. Some do not.</p><p>Color is one of the primitives that must stay dynamic, because both UIKit and SwiftUI already have appearance-aware models for it. If your design system exposes color as static values only, the UI will drift or break in one of the frameworks sooner rather than later.</p><p>Font is a different story. Typography is often far less dynamic and much more identity-driven. Most of the time, mapping font tokens consistently across UIKit and SwiftUI is enough. Trying to vary fonts by color scheme usually adds noise instead of improving UX.</p><div><hr></div><h2>Design System Takeaway</h2><p>If UIKit is already deep in the app, you do not always need to &#8220;win&#8221; the framework argument first.</p><p>A more useful first step is to ask:</p><ul><li><p>Which tokens must remain reactive across both frameworks?</p></li><li><p>Which tokens should stay stable regardless of appearance?</p></li><li><p>Which ones break UX immediately if they do not adapt?</p></li></ul><p>Color lands in the first group.</p><p>That is the part worth solving early, because once light and dark mode stop behaving consistently, the product feels broken no matter how modern the view layer looks.</p><div><hr></div><h2>Is Migration Worth It</h2><p>In a legacy project, the right choice between SwiftUI and UIKit is often less about ideology and more about where the architecture already lives.</p><p>If UIKit is still the structural core, that is fine. The more important thing is whether the pieces you share between UIKit and SwiftUI preserve the behaviors users already expect.</p><p>And for a design system, dynamic color support is one of the most important of those behaviors.</p><p>UIKit already gives you dynamic colors through <code>UIColor(dynamicProvider:)</code>. SwiftUI already gives you environment-driven appearance updates through <code>colorScheme</code> and context-resolved <code>Color</code>. So the real job is not inventing a third model. It is making sure your design-system colors stay dynamic no matter which UI layer consumes them. That is what keeps the UI working when appearance changes, including after the app returns and the trait environment has changed.</p><div><hr></div><h2>References</h2><ul><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/uikit/uicolor/init(dynamicprovider:)">UIColor(init(dynamicProvider:))</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/uikit/color-creation">Color creation</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/uikit/uitraitchangeobservable/registerfortraitchanges">registerForTraitChanges(_:handler:)</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/swiftui/environmentvalues/colorscheme">EnvironmentValues.colorScheme</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/swiftui/color">Color</a></p></li><li><p>Apple Developer Documentation: <a href="https://developer.apple.com/documentation/swiftui/environmentvalues">EnvironmentValues</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[ WWDC26: SwiftData Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-swiftdata-group-lab-q-and</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-swiftdata-group-lab-q-and</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Thu, 18 Jun 2026 12:02:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/46357848-7328-4082-b196-ad8e976b8217_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This lab focused on SwiftData and Core Data topics: widgets and app intents, large datasets, previews and sample data, Results Observer, aggregate queries, nonoptional model creation, CloudKit, app groups, schema evolution, counting, performance, sync behavior, Codable types, multiple model contexts, grouped queries, and model actors.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>What is the proper way to use SwiftData with widgets, App Intents, and Shortcuts?</h2><p>Use an app group when the app and widget or extension need to share the same SwiftData store.</p><p>The panel recommended making the main app the process that owns migration. Widgets and extensions can read and write the shared database after the app has prepared it, but they should not be responsible for schema migration.</p><p>For widgets and extensions, do not include the schema migration plan. If the widget starts before the user launches the updated app, use the error path to show UI asking the user to open the app first so the app can run migration.</p><p>The Sample Trips app was mentioned as an example that includes a widget and uses a group container to share data.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=282s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers approach large datasets in SwiftData?</h2><p>First identify what &#8220;large&#8221; means for the app.</p><p>If the app has many rows, index the fields used for filtering and sorting. Also use fetch limits and predicates so the app does not pull more objects into memory than it needs.</p><p>If each row contains large binary data, use external storage for large data blobs. That allows the database to keep the bytes outside the main store file.</p><p>For large imports, use smaller batches and short-lived model contexts. Insert a batch, save it, discard that context, then continue with the next batch. This keeps memory pressure lower and avoids one context accumulating too much work.</p><p>Use Instruments to validate assumptions. The hitches instrument can show UI problems, and the persistence instrument can show what SwiftData is actually fetching under the hood.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=403s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the best way to create sample data for SwiftData previews and tests?</h2><p>For previews, use preview traits and seed expressive data into an in-memory or preview-specific container.</p><p>The Sample Trips app uses preview traits to seed preview data. The panel recommended making preview data diverse enough to exercise the UI: long names, many rows, and different shapes of data.</p><p>You can also run a query inside a preview and use its result to drive the previewed view.</p><p>For migration testing, sample data matters in a different way. Keep a corpus of previous stores from earlier app versions. Test migration from each shipped schema, not only the most recent one, because users can update after skipping versions for a long time.</p><p>The panel also mentioned that AI coding tools can be useful for generating varied sample data.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=565s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When should developers use Results Observer instead of <code>@Query</code>?</h2><p>Use Results Observer when you want an observable fetch outside a SwiftUI view.</p><p><code>@Query</code> is tied to SwiftUI&#8217;s view lifecycle. Results Observer gives similar observable-fetch behavior in places such as view models or other non-view code.</p><p>Performance is broadly similar because the underlying fetch behavior is similar. The main difference is the API shape and whether it participates directly in SwiftUI lifecycle.</p><p>History Observer is different: it helps catch up with store changes over time. It is useful when you need to replicate changes, filter by author, or know which changes happened since a point in time.</p><p>Both Results Observer and History Observer reduce the need to manually listen for notifications and decide when to refetch.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=735s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should SwiftData apps handle aggregate values such as sums, averages, min, and max?</h2><p>For min and max, a fetch limit of one plus a sort descriptor can solve many cases.</p><p>For more general aggregate expressions such as sums and averages, the panel acknowledged this is a gap compared with Core Data&#8217;s older <code>NSExpression</code> workflows. They asked developers to file feedback with concrete use cases, not only &#8220;I used this before.&#8221;</p><p>If an app needs an aggregate feature that SwiftData does not currently expose, one workaround is coexistence: use SwiftData and Core Data stacks pointing at the same store, and use Core Data for the missing aggregate operation.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=927s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should a SwiftUI + SwiftData app create a new model with non-optional attributes?</h2><p>If a SwiftData model has nonoptional properties, set them in the initializer.</p><p>If a view needs a single existing model object, it is often cleaner to fetch that object outside the child view. The parent can decide whether to show the real view, create the object, or show an unavailable state.</p><p>For one-object fetches, use <code>ModelContext</code> directly with a fetch limit instead of forcing the view body to handle an empty <code>@Query</code> array. That keeps creation and lookup logic outside the SwiftUI rendering path.</p><p>The panel&#8217;s general advice was to give the view a real model to work with instead of making the body contain too much &#8220;does this exist yet?&#8221; logic.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=1032s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can an app add an app group or versioned schema later without losing existing SwiftData + CloudKit data?</h2><p>A versioned schema can be added later.</p><p>For app groups, moving the store changes the store location. If the app previously used the default model configuration, SwiftData can move the data for you. If the app previously specified a custom store URL, then the app needs to move the data itself.</p><p>To introduce versioned schemas, start with the schema the app currently has and make that the first versioned schema. From there, build future versions and migration plans progressively.</p><p>The panel said sample code for this migration path would be useful feedback.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=1240s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How does using an app group for a SwiftData store interact with CloudKit development and production environments?</h2><p>Be careful about which process owns CloudKit sync.</p><p>If multiple apps, widgets, or extensions share a SwiftData store in an app group, they all need appropriate entitlements if they are expected to sync the CloudKit-backed store.</p><p>But widgets and extensions often should not be the processes doing CloudKit sync. They have less time and different runtime constraints. The panel suggested a cleaner pattern: let the main app own the CloudKit-syncing store, and use a separate local app-group store when extensions or widgets need local shared data.</p><p>This avoids requiring a widget to perform expensive sync work and keeps sync behavior in the process best suited for it.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=1398s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers handle schema evolution while multiple apps or targets share a CloudKit-backed store?</h2><p>Make sure the apps agree on schema.</p><p>The panel warned against competing migrations. You do not want one app adding a column while another app removes it, or different targets shipping incompatible model definitions.</p><p>During development, learn from testing, align schemas across apps, and eventually push the schema to production. Then test production CloudKit sync as well, not only development sync.</p><p>The short version from the panel: sync is hard, so keep the schema story disciplined.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=1520s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the most performant way to count SwiftData objects without querying them in a view?</h2><p>Use <code>fetchCount</code> on <code>ModelContext</code>.</p><p>If the app only needs a count, it should not fetch all objects and count them in memory. Ask the model context for the count directly.</p><p>For performance-sensitive views, it is also fine to fetch manually outside <code>@Query</code> when that gives you more control. But if you cache manually, you must own cache invalidation.</p><p>The panel recommended combining the SwiftUI instrument and the persistence instrument. Sometimes the expensive-looking problem is I/O, but the real cause is a SwiftUI view invalidating too often and triggering repeated fetches.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=1636s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can SwiftData + CloudKit apps make synchronization happen as quickly as possible?</h2><p>First make sure the data is actually saved.</p><p>Autosave can take a few seconds, and if you stop the app from Xcode before autosave fires, the data may never be saved and therefore cannot sync. During testing, background the app instead of force-stopping it.</p><p>Check entitlements carefully, especially differences between debug and release configurations. If pushes are not arriving, that can affect sync timing.</p><p>Different devices also have different policies. Apple Watch may be more conservative about networking, especially off the charger or on cellular. Phones may throttle work under thermal pressure.</p><p>If sync behaves unexpectedly, collect sysdiagnose from all relevant devices and file feedback so Apple can inspect what happened.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=1932s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the best way to store enums, Codable types, and associated values in SwiftData?</h2><p>Raw-representable enums are improving, including predicate support this year.</p><p>For associated values or types SwiftData cannot map cleanly into a schema, Codable can work as long as the values are Codable. New this year, developers can explicitly mark attributes to be treated as Codable.</p><p>The tradeoff is queryability. If a value is stored as encoded data, SwiftData cannot reason about the inner structure for predicates and sorting.</p><p>If you need to query or sort by parts of the value, model those parts explicitly with SwiftData models and relationships, then expose an enum-like computed API to the rest of the app.</p><p>The panel mentioned types like MapKit data or Foundation <code>Measurement</code> as examples where Codable storage can be useful when you do not own the underlying type or cannot model it directly.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=2178s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are best practices for using multiple model contexts?</h2><p>Model contexts are working sets and transaction boundaries.</p><p>Use separate contexts when work is meaningfully independent, especially background work or batch imports. Keep background contexts short-lived so they do not accumulate too much memory.</p><p>Do not assume &#8220;more contexts&#8221; always means &#8220;more performance.&#8221; The panel emphasized that I/O is often the bottleneck, and too much concurrency can add coordination overhead, memory pressure, and diminishing returns.</p><p>SQLite allows multiple readers and one writer with WAL journaling. That means concurrent reads can happen while a write is active, but write coordination still matters.</p><p>Benchmarking is hard because caches exist at many layers: SQLite page cache, file-system cache, and storage-controller behavior. Use the I/O instrument and persistence instrument to understand what is actually happening.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=2578s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers fetch only the data they actually need?</h2><p>Be specific in the fetch.</p><p>Use predicates, sort descriptors, fetch limits, and identifiers rather than pulling large object graphs into memory. Matthew&#8217;s analogy from the panel: do not ask the library reference desk for every book and then sort through them yourself. Ask for the books you actually need.</p><p>If you only need identifiers, fetch identifiers. If you only need a count, fetch the count. If you only need a subset, make the predicate describe that subset.</p><p>This reduces memory pressure, avoids unnecessary I/O, and makes SwiftUI-driven views less likely to amplify performance problems.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=3020s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should developers know about grouped queries and sectioning in SwiftData?</h2><p>SwiftData now has better support for sectioned / grouped observable fetches.</p><p>The panel referenced the new results observer support for sectioning. This helps when developers previously had to fetch data and manually group it themselves for UI presentation.</p><p>Sectioning is useful when the UI naturally groups objects, such as by date, category, trip, or another derived grouping key.</p><p>The performance guidance stays the same: make sure the grouping and filtering are represented in the fetch as much as possible, index where appropriate, and use Instruments if the grouping operation appears expensive.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=3565s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers think about model actors and <code>Sendable</code> boundaries in SwiftData?</h2><p>Use model actors to isolate SwiftData work across concurrency domains.</p><p>The panel discussed the importance of not casually passing live model objects across concurrency boundaries. SwiftData models are tied to their model context, and contexts are not something you should freely share across unrelated tasks or actors.</p><p>A model actor gives you a structured place to perform database work. Instead of passing full model instances everywhere, pass identifiers or values, then fetch or operate on the model inside the actor or context that owns the work.</p><p>This keeps concurrency safer and makes it clearer which context owns each operation.</p><p><a href="https://www.youtube.com/watch?v=Sfl1uLmL32I&amp;t=3644s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and asked practical SwiftData questions throughout the session. Your questions made the discussion useful for developers working with SwiftData, Core Data, widgets, app intents, large datasets, previews, migrations, Results Observer, CloudKit, app groups, performance, sync, Codable values, multiple contexts, grouped queries, and model actors.</p><p>Question acknowledgments: the developers who asked about widgets and App Intents, large datasets, sample data, Results Observer, aggregate queries, nonoptional model creation, CloudKit, app groups, counting, sync behavior, enums, Codable types, multiple model contexts, grouped queries, and actor isolation.</p><p>Finally, a heartfelt thank-you to Kurt, Rishi, David, Thomas, Ben, and the teams behind the scenes for sharing practical SwiftData and persistence guidance.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: SwiftUI Group Lab 2nd - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-swiftui-group-lab-2nd-q-and</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-swiftui-group-lab-2nd-q-and</guid><pubDate>Thu, 18 Jun 2026 06:02:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/238957f5-6a7e-4417-b816-e63daaf44e2b_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This lab focused on SwiftUI architecture, performance, navigation, Liquid Glass, layout, data flow, identity, type erasure, overlays, previews, animation, UIKit interop, and SwiftUI&#8217;s evolution.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>What should developers do when very large reorderable collections are slow in SwiftUI?</h2><p>The panel said this is a known issue and encouraged developers to file feedback.</p><p>The important part of the feedback is not just &#8220;this is slow,&#8221; but the real use case: why the app needs that many items, what the data represents, and what structure the app is trying to build.</p><p>Apple already knows there are issues in this area, but concrete feedback helps the team make sure the APIs support real-world needs rather than only synthetic cases.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=284s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can developers create custom navigation transitions in SwiftUI?</h2><p>Not today in the same way UIKit allows custom transition objects.</p><p><code>NavigationTransition</code> is currently a protocol used by SwiftUI to expose concrete built-in transitions, such as zoom, crossfade, and automatic. Developers can use those transitions, but the protocol does not currently expose the pieces needed to build an arbitrary custom navigation transition.</p><p>The panel recommended filing feedback with the specific custom transition use case. If the transition does not need to be tied to a <code>NavigationStack</code>, developers can still build many custom effects with SwiftUI animation, animatable values, keyframes, modifiers, and shaders.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=391s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers use Xcode coding intelligence for Liquid Glass UI work?</h2><p>The new Xcode skills can help agents understand new APIs, design guidance, and best practices.</p><p>The panel said Xcode&#8217;s agent workflows and built-in tools are useful for iterating on Liquid Glass because previews can render the UI and help validate visual changes.</p><p>Developers can also export Xcode&#8217;s skills and use them with other agentic systems. The skills are targeted at models, but they are also useful for humans to read because they contain practical design and API guidance.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=547s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When should I use <code>.glassEffect</code>, glass button styles, and toolbar glass?</h2><p>Use the system-provided glass treatment when possible.</p><p>Buttons placed in toolbars or navigation bars generally get the appropriate glass appearance automatically. If you want a tinted or prominent control there, use tint or the relevant system button style rather than layering your own glass effect on top.</p><p>The panel warned that <code>glassEffect</code> is often not the right tool for ordinary buttons. If you want a glass button, use the glass button style or prominent glass style, and then shape it with APIs such as button border shape.</p><p>Liquid Glass is usually best in the control layer, above scrolling content. If there is no content underneath for the glass to refract, the effect may not add much value and can make the UI heavier than necessary.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=650s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should apps handle all the new resizable window sizes and layouts?</h2><p>Do not hard-code fixed window sizes.</p><p>Use size classes as broad experience categories, but remember that windows can still have many intermediate sizes. The app should remain flexible between size-class boundaries.</p><p>System containers are usually a good first choice because SwiftUI can handle much of the adaptation for you. Adaptive <code>TabView</code>, sidebars, <code>ViewThatFits</code>, custom layouts, custom containers, <code>AnyLayout</code>, and layout protocols are all useful tools.</p><p>The panel especially recommended preserving structural identity when changing layout. Avoid switching entire view trees with <code>if</code> statements when a layout change can reposition the same child views instead.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=950s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Should I use <code>GeometryReader</code> for responsive SwiftUI layouts?</h2><p>Usually prefer <code>onGeometryChange</code> or custom layouts.</p><p><code>GeometryReader</code> can be expensive when views are placed inside its closure, especially if it causes invalidation every frame. Historically, a safer use was often in a background view.</p><p><code>onGeometryChange</code> is useful because it has a transform closure and an action closure. The transform can reduce high-frequency geometry changes into coarser states, such as &#8220;small,&#8221; &#8220;medium,&#8221; or &#8220;large,&#8221; so the action fires only when the value actually changes.</p><p>For complex placement, use custom layouts. A custom layout can often compute everything in one layout pass, while a geometry-change-plus-state approach may require an initial pass and then a second pass after state changes.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=1259s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers learn SwiftUI data management and passing data between views?</h2><p>Build small apps around data you actually understand.</p><p>The panel said SwiftUI is architecture-agnostic because there is no single correct architecture for every app. The right data model depends on the shape of the app&#8217;s data.</p><p>A good learning path is to build self-contained models, state machines, and logical components, then keep views lightweight. Views should map data to UI, not accumulate too much business logic.</p><p>Use Instruments and the SwiftUI instrument to understand how data changes cause views to update. This can show which view bodies run, what SwiftUI is doing, and how data actually flows through the app.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=1427s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When should I use <code>DynamicProperty</code> instead of <code>onChange</code> or <code>onAppear</code>?</h2><p>Use <code>DynamicProperty</code> when you need a reusable property wrapper that can prepare or expose data before <code>body</code> runs.</p><p>The panel said <code>onChange</code> is useful when you truly need an imperative reaction, especially to communicate with an external system. But if you are using <code>onChange</code> only to mutate view state from other state, that is often a sign the data model should compute and vend the value directly.</p><p><code>DynamicProperty</code> can avoid an extra render cycle because its <code>update()</code> method runs before <code>body</code>. That makes it useful for cases like loading cached data before the first render, rather than waiting for <code>onAppear</code> and triggering a second render.</p><p>The panel also noted that <code>task</code> and <code>onAppear</code> now have more consistent ordering thanks to Swift concurrency improvements.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=1616s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Should I use <code>if</code> statements to conditionally hide elements in SwiftUI?</h2><p>It depends on whether the view is really being removed or only visually hidden.</p><p>If a view should remain part of layout and only fade in or out, use an inert modifier value such as <code>opacity(0)</code> or <code>opacity(1)</code>rather than changing the view hierarchy.</p><p>If the view truly should be removed from layout, then a conditional can be appropriate. But conditionals can reset state and cause layout reflow because SwiftUI may see a different structural view.</p><p>Be careful with conditional view modifiers and &#8220;if modifier&#8221; helpers. They can hide conditional branches inside modifiers and unexpectedly reset state or change layout upstream.</p><p>Lazy containers are a special case: top-level conditionals inside rows can make it harder for SwiftUI to know how many views a row resolves to. Wrapping content in a unary container such as <code>VStack</code> can help preserve the container&#8217;s expectations.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=1933s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the concrete cost of type erasing with <code>AnyView</code>?</h2><p><code>AnyView</code> is not forbidden, but it can hide useful type information from SwiftUI.</p><p>If the underlying type changes, SwiftUI may need to tear down and rebuild that part of the hierarchy, similar to switching branches in an <code>if</code> statement. That can reset state and reduce performance.</p><p><code>AnyView</code> can also be problematic in lazy containers because the container cannot easily know how many views the erased content resolves to.</p><p>If you must type erase, try to keep the underlying type stable. If the problem is only that a lazy container needs a single resolved view, wrapping content in a unary container such as <code>VStack</code> can help.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=2395s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers use resizable previews to improve adaptive layouts?</h2><p>Resize your previews and see where the app breaks.</p><p>The panel said the question is almost backwards: now that previews are resizable, developers should use them to find assumptions in their layout. Resize the app, inspect what fails, and remove hard-coded magic numbers or fragile layout assumptions.</p><p>Also use the app in real resizable environments such as iPad multitasking, macOS, visionOS, or iPhone mirroring. Look at other apps for inspiration, especially indie apps that solve compact and expanded layouts creatively.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=2475s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can I present a full-screen overlay above everything else, including sheets?</h2><p>There is no simple SwiftUI-first API that guarantees this across all modal presentation layers.</p><p>The panel discussed common cases such as showing a login screen over the entire app when a session expires. A <code>fullScreenCover</code> can work if you control the presentation level, but it becomes complicated if other sheets or modals are already presented above that level.</p><p>The best SwiftUI answer is to coordinate navigation and presentation state centrally so you know what is currently presented and can choose the right presentation level.</p><p>If you truly need something above all SwiftUI presentations, UIKit interop may be required. A separate <code>UIWindow</code> can sometimes solve app-global overlay cases, but it also requires careful lifecycle and scene management.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=2655s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should custom pure SwiftUI controls handle focus, keyboard behavior, accessibility, and platform conventions?</h2><p>Use system controls when they fit, and be careful when replacing them.</p><p>The panel&#8217;s guidance was that controls are not just visuals. System controls carry lots of platform behavior: focus, keyboard interaction, accessibility, hit testing, state, platform styling, and adaptation across devices.</p><p>If you build a pure SwiftUI control, you need to think through those behaviors explicitly. It is not enough to draw something that looks like a button, picker, or slider. The control also needs to behave correctly for VoiceOver, keyboard navigation, focus, pointer or touch input, and platform expectations.</p><p>The best path is to compose from existing SwiftUI controls and styles where possible. If you need a fully custom control, test it across platforms and accessibility modes, not only in the default visual state.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=3149s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the best way to split large SwiftUI views: smaller <code>View</code> structs or <code>@ViewBuilder</code> computed properties?</h2><p>Split based on data dependencies, not line count.</p><p>The panel said the benefit of smaller views is not simply that the file is shorter. The benefit is giving SwiftUI boundaries where it can compare inputs and skip work when a dependency has not changed.</p><p>If a header, content area, and footer depend on different pieces of state, those can be good candidates for separate <code>View</code>structs. Then a change in one dependency does not necessarily invalidate the entire parent body.</p><p>A <code>@ViewBuilder</code> computed property can make the code look cleaner, but it is still functionally part of the same large body. It does not create the same dependency boundary that a separate view can create.</p><p>So use computed properties for readability, but use separate view structs when you want SwiftUI to isolate update dependencies and avoid unnecessary body work.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=3398s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the panel most proud of in SwiftUI&#8217;s evolution?</h2><p>The panel&#8217;s final answers centered on how far SwiftUI has come as both a declarative UI framework and a Swift-native programming model.</p><p>They highlighted performance work, layout improvements, better integration with Swift&#8217;s type system and concurrency model, and the growing ability to express complex UI in a way that stays readable and adaptable.</p><p>They also emphasized the ecosystem: SwiftUI is not only the framework surface, but also previews, Instruments, Xcode skills, UIKit/AppKit interop, and the broader set of tools that help developers build and understand apps.</p><p>The final message was that SwiftUI keeps evolving because developers keep pushing it with real apps, real feedback, and increasingly demanding UI patterns.</p><p><a href="https://www.youtube.com/watch?v=emR88Imk2lc&amp;t=3593s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and asked practical SwiftUI questions throughout the session. Your questions made the discussion useful for developers working with Liquid Glass, navigation transitions, resizable windows, custom layouts, geometry, data flow, dynamic properties, view identity, type erasure, overlays, previews, UIKit interop, and SwiftUI performance.</p><p>Question acknowledgments: the developers who asked about large reorderable collections, custom navigation transitions, coding intelligence with Liquid Glass, adaptive layouts, data management, conditional hiding, <code>AnyView</code>, resizable previews, full-screen overlays, custom controls, splitting large views, and the evolution of SwiftUI.</p><p>Finally, a heartfelt thank-you to Kurt, Anna, Stephen, Nick, Russell, Sam, and the teams behind the scenes for sharing practical SwiftUI and UI framework guidance.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: App Store Connect Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-app-store-connect-group-lab</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-app-store-connect-group-lab</guid><pubDate>Wed, 17 Jun 2026 12:03:54 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3bb2daad-0979-47f5-9154-8bd2dca4e8bc_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This lab covered practical App Store Connect workflows: App Store Connect APIs, TestFlight, App Review preparation, subscriptions, retention messaging, analytics, API key security, universal purchase, localization, product pages, and app visibility.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>What App Store Connect APIs or capabilities are overlooked and worth using today?</h2><p>The panel highlighted build upload automation, TestFlight feedback APIs, webhooks, and reports.</p><p>Build uploads can automate much of the development loop: upload a build, make it available to TestFlight testers, collect feedback, act on that feedback, and upload another build.</p><p>The TestFlight feedback APIs and webhooks are useful because teams can automatically create tickets in their own systems when testers submit feedback.</p><p>The panel also called out power and performance reports. These let developers download data about how the app is doing on real devices, including areas such as storage and CPU usage.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=277s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should a game with no sound signal that it is accessible for people with hearing disabilities?</h2><p>Do not claim captions if the app does not have captions.</p><p>The panel suggested answering the accessibility nutrition-label questions as accurately as possible. If the game has no sound, then captions may not be the right declaration.</p><p>Instead, use other App Store metadata to explain the accessibility story. The app description can state that the game is fully playable without sound. App previews and screenshots can also show the experience and communicate the value proposition clearly.</p><p>The broader guidance was to be accurate in the formal accessibility declarations and use product-page copy and media to explain context that the labels do not capture perfectly.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=379s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are common reasons subscription apps get rejected on first review, and how can developers recover quickly?</h2><p>Preparation is the main protection against first-review rejection.</p><p>Test on a real device the way users will use the app. Make sure subscriptions and in-app purchases work in the sandbox and through TestFlight. Confirm production services are ready, flows do not crash, and the paywalled parts of the app are accessible to App Review.</p><p>For subscription apps, provide review credentials and clear App Review notes. If content is behind a paywall, reviewers need a way to see it.</p><p>If the app is rejected, read the detailed message carefully and respond in App Store Connect. Do not only upload a new binary. Use the response space to explain how the app works, clarify anything the reviewer may have missed, and ask specific questions if the rejection is unclear.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=460s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Will retention messaging analytics show impressions, save rate, and cancel-flow behavior?</h2><p>Yes, App Store Connect will provide data for retention messaging.</p><p>The panel said developers will be able to see how many people saw the retention message, how many people clicked cancel, and how many chose to stay subscribed.</p><p>Developers can also test different messages and offers to see what resonates. Retention messaging can remind users of the value of the subscription before they cancel, and analytics help measure whether that message is effective.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=632s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are common security mistakes when integrating with the App Store Connect API?</h2><p>Do not hardcode API keys or ship them in client apps.</p><p>Keep private keys on your server or in secure automation infrastructure. Do not commit them to repositories, embed them in apps, or share them broadly with third parties.</p><p>If a key is compromised, revoke it in App Store Connect. If you created a key for a specific service or use case and stop using that service, revoke the key.</p><p>Use the principle of least privilege. Give each key only the permissions it needs. If integrating with a third party, be especially careful about both the access level and the lifetime of the key.</p><p>The panel also mentioned users-and-access APIs as a way to monitor who has access to your account and compare that against internal systems.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=695s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can App Store Analytics show organic manual updates versus background auto-updates?</h2><p>Yes, but the breakdown is available in reports, not everywhere in the dashboard.</p><p>The panel said App Store Connect has multiple places to get update data. The dashboard has update-related data, but the auto-update versus manual-update breakdown is in analytics reports.</p><p>Download the analytics report and look for the column that breaks down automatic versus manual updates.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=823s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can a team API key be limited to only a few apps for CI uploads?</h2><p>A general team API key cannot be scoped to only a few apps.</p><p>The panel explained that team keys can have roles, but general access keys are not scoped to specific apps.</p><p>One alternative is an individual API key tied to a specific App Store Connect user. That key inherits that user&#8217;s access level. If the user only has access to a few apps, the key follows that access.</p><p>The tradeoff is lifecycle management. If the person leaves the company or loses access, automation depending on that individual key can break. For CI systems, be deliberate about whose key is used and how it is maintained.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=865s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can universal purchase apps use different names and subtitles per target or platform?</h2><p>No, name and subtitle are shared across the universal purchase app.</p><p>The panel explained that some metadata is shared across all platforms because the app is considered one app across the ecosystem. The shared information includes name, subtitle, age rating, and genre.</p><p>The description can differ by platform. If the tvOS version does not support NFC, for example, the tvOS description can avoid mentioning NFC while the iOS description can describe it.</p><p>The recommendation is to use platform-specific descriptions to explain differences while keeping the shared identity consistent.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=997s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Does the new retention workflow support localization?</h2><p>Yes.</p><p>Retention messaging supports localization, and the panel recommended keeping retention messages consistent with the app&#8217;s own localizations.</p><p>If a user moves from a fully localized app experience into an English-only cancellation or retention flow, the experience can feel disjointed. Match the user&#8217;s language when possible.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=1081s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are best practices for App Store app descriptions?</h2><p>Write for the user, not just for density.</p><p>The panel recommended thinking about what users actually need to know to decide whether the app is useful. Dense copy can include a lot of information, but it may not be enticing or easy to scan.</p><p>Use other App Store surfaces too. Screenshots, app previews, custom product pages, product page optimization, custom product page headers, and search-result creative assets can communicate value visually.</p><p>Custom product pages can also let you tailor copy to different audiences, and product page optimization can help test whether shorter or different descriptions perform better.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=1143s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are best practices for using TestFlight for internal and external testing?</h2><p>Start with internal testing, then move to external testing when the app is more ready.</p><p>Internal TestFlight is best for people inside your App Store Connect team, such as developers, QA, localization, leadership, or other internal groups. You can create different internal groups and decide which builds each group receives.</p><p>External TestFlight requires Beta App Review. Once approved, you can invite up to 10,000 external testers. Use public links or communities relevant to your app to find testers, but approach it as asking for feedback rather than selling.</p><p>The panel also noted that TestFlight itself is tested through internal TestFlight at Apple, which reinforces that it is meant for real pre-release workflows.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=1257s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What advice applies to API keys used in automation scripts, tooling, or apps?</h2><p>Keep API keys on the server side and apply least privilege.</p><p>The panel repeated that private keys should not go into client apps. They should live in backend systems or secure automation infrastructure.</p><p>Team keys do not expire automatically, so developers need to manage their lifecycle carefully. For testing or exploration, individual keys can be useful because they inherit the permissions of the user who created them.</p><p>When a key is created for a specific purpose, use it only for that purpose. If the use case ends, revoke it.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=1460s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can the same product name be used for separate Mac and iOS / visionOS app listings?</h2><p>No, not if they are separate app records with different bundle IDs.</p><p>The panel said this has not changed. Product names need to remain unique because users may be able to download related apps across platforms, and the store needs to disambiguate them.</p><p>The recommended approach is to consider universal purchase. Adding the Mac app to the iOS and visionOS app record can provide the shared name and may unlock other ecosystem benefits over time.</p><p>The panel acknowledged that merging app records and migrating users can be work, but universal purchase can be the better long-term direction when the apps are meant to be one product.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=1563s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should a first-time developer with user authentication and third-party API keys get right before App Review?</h2><p>Make sure production services are ready and privacy expectations are met.</p><p>Test authentication thoroughly. Test the third-party API integrations. Make sure keys, tokens, and backend systems are ready for production traffic and scale.</p><p>If users provide their own API keys, the app needs to manage those keys in a privacy-conscious way.</p><p>Also provide App Review with demo account information and clear review notes so reviewers can exercise the app fully.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=1687s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can a paid-upfront app transition to a freemium or premium model while honoring prior purchases?</h2><p>Use StoreKit 2&#8217;s app transaction API to identify the original app version a customer purchased.</p><p>The panel explained that <code>AppTransaction</code> can expose the original app version, which can help you determine whether a user bought version 1 before the business-model change.</p><p>Test with Xcode, sandbox accounts, and TestFlight. TestFlight uses the sandbox environment for in-app purchase behavior, but if you need sandbox account controls, explicitly sign into the sandbox account.</p><p>One practical workflow is to download the current App Store version with one account, then upgrade to the TestFlight build and verify the restoration or entitlement behavior.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=1748s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the best way to learn the step-by-step process for publishing a first iOS app?</h2><p>Start with Apple&#8217;s developer resources and App Store Connect help guides.</p><p>The panel recommended <a href="http://developer.apple.com/">developer.apple.com</a> tutorials, documentation, WWDC sessions, the App Store Connect help guide, and the Apple Developer Pathway for publishing a first app.</p><p>For TestFlight specifically, the panel mentioned a &#8220;Getting started with TestFlight&#8221; tech talk that walks through building, testing, and moving toward App Review.</p><p>The overall path is: build the app, test locally, test with TestFlight, prepare metadata and review notes, submit to App Review, respond to review if needed, and release after approval.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=1916s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can developers increase visibility for an app?</h2><p>Use strong creative assets and the App Store discovery tools.</p><p>The panel recommended screenshots, app previews, custom images, videos, product page headers, and search-result assets to make the app&#8217;s value clear.</p><p>Developers can also use in-app events, custom product pages, keyword-linked custom product pages, product page optimization, and feature nominations.</p><p>If an app is featured as App of the Day or Game of the Day, App Store Connect can create a shareable moment card that developers can use outside the App Store.</p><p>Shareable moments are also available for new app versions, which helps bring users back to the App Store listing.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2046s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Does a universal app need a different binary for every platform?</h2><p>It depends on the platforms and how native you want each experience to be.</p><p>You can start with one platform and add others later. For example, an iOS app can be made available on macOS or visionOS when eligible, and later you can add a platform-specific native binary if you want to use more native features.</p><p>A watchOS app usually has its own app experience, especially if it is paired with an iOS app.</p><p>The key point: universal purchase does not mean every platform must ship all binaries immediately. You can expand step by step.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2152s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Should App Review notes be in English, or can developers use their native language?</h2><p>Developers do not need to speak English to be on the App Store.</p><p>The App Review team has broad language coverage and reviews apps in many languages. English may be helpful in some cases, but it is not an absolute requirement.</p><p>If your native language is not English, you can still provide review notes in that language. When possible, Apple will match reviewer language skills to the app and submission context.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2267s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What new App Store Connect workflows should mature automation users revisit this year?</h2><p>Even teams with mature automation should revisit analytics, Game Center submissions, in-app purchases, offer codes, build delivery, and TestFlight feedback.</p><p>The panel highlighted over 100 new metrics for subscription and in-app purchase businesses. Those metrics are available through APIs, but App Store Connect web also has new visualizations that automation-heavy teams may not have seen.</p><p>Game Center entities such as leaderboards can now be submitted through newer workflows. In-app purchases are also part of the enhanced submission experience. Offer code APIs now support consumables and non-consumables.</p><p>The build delivery API from the previous year remains important for teams that want to automate build trains and submissions.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2339s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the most common reasons apps get rejected on the App Store?</h2><p>Many common rejections come from being underprepared for review.</p><p>The panel called out crashes, bugs, incomplete information, missing demo credentials, untested flows, and not testing on real devices.</p><p>Review the App Review Guidelines carefully, especially sections that apply to your app category.</p><p>Use TestFlight to get feedback before submission. Solo developers should still ask friends, family, or external testers to exercise the app, because App Review may find issues the developer never hit on their own device or simulator.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2450s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Which app metadata or capability changes are only validated after upload, and will more checks move into Xcode?</h2><p>Apple validates throughout the pipeline and is always trying to move feedback earlier.</p><p>The panel did not list every validation, because there are many. But they emphasized that App Store Connect and Xcode already provide errors and warnings at different stages.</p><p>Developers can validate an app in Xcode before delivery to catch some issues earlier. Uploading frequently through a continuous delivery workflow can also surface issues sooner.</p><p>The general direction is to move more checks earlier in the development process whenever possible.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2650s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can TestFlight builds be organized into streams or groups for parallel feature and bug-fix testing?</h2><p>Yes.</p><p>TestFlight groups are designed for this. A group is a combination of testers and the builds that group can access.</p><p>You can create separate groups for QA, localization, leadership, power users, a major future feature, and a bug-fix release. Each group only sees the builds assigned to that group.</p><p>This allows parallel testing. For example, one group can test a long-running 3.0 feature branch while another group tests a 1.1 bug-fix build.</p><p>Xcode Cloud can help automate this by tying branches to workflows and distributing builds to the right TestFlight groups.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2767s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Why is there a delay before price changes for in-app purchases or subscriptions go live?</h2><p>The goal is for the price to go live consistently across regions.</p><p>The panel explained that the delay helps App Store Connect propagate the change and coordinate it across time zones so pricing can change globally in a predictable way.</p><p>This applies even when lowering the price, because the store still needs time to prepare and align the change.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2930s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers merge separate regional app listings into one app listing when features differ by country?</h2><p>Choose the app record you want to keep, then migrate users and functionality toward that persistent listing.</p><p>The panel said Apple did something similar with Creator Studio. The practical first step is deciding which app listing should survive, often based on the app&#8217;s strongest existing presence, ratings, users, or business needs.</p><p>When features differ by country, use localization, availability, server-side feature flags, and region-aware product copy to explain or control differences.</p><p>The goal is to avoid maintaining duplicate app records when the products are fundamentally the same core app, while still respecting regional differences in features, regulations, or content.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=2968s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should developers know about the new product page header and search-result assets?</h2><p>The new creative assets are meant to make an app&#8217;s value visible before users read dense text.</p><p>The panel framed the product page header as one of the first things users will see. A compelling custom image or video can communicate value faster than a long description.</p><p>Search-result assets are another placement where custom images and videos can help the app stand out. The asset library in App Store Connect is also useful because it lets developers manage images and reuse them across different placements.</p><p>The practical advice is to treat description copy and creative assets as complementary. Use visuals to make the app&#8217;s purpose and quality obvious, then use description text for factual detail.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=3103s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What changed in App Store Connect analytics for subscriptions and in-app purchases?</h2><p>App Store Connect now has a much richer customer-journey view for subscription and in-app purchase businesses.</p><p>The panel described visualizations that show the journey from download, to purchase, to subscription renewal. Developers can see what percentage of downloaders convert to paid users, and what percentage of paid users continue paying over time.</p><p>The goal is to help developers identify soft spots in the business. If users download but do not convert, or convert but do not renew, the analytics can point to where improvements are needed.</p><p>The panel also highlighted new benchmarks. Benchmarks help developers understand whether a metric is strong or weak compared with similar apps, and can provide a roadmap for what to focus on next.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=3141s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What makes a successful featuring nomination submission?</h2><p>A strong featuring nomination starts with an app that is interesting, polished, and clearly differentiated.</p><p>The panel said novelty matters. If an app is in a crowded category, it may be harder to stand out unless it does something meaningfully new or especially well.</p><p>Great art can also help separate an app from the crowd. App Store editorial presentation is visual, so strong creative assets can make the story easier to understand.</p><p>The practical takeaway is to make the nomination easy to evaluate: explain what is new, why it matters, what audience it serves, and what makes the app timely or editorially interesting.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=3262s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>My app users paste their own App Store Connect API keys into my third-party tool. What least-privilege setup should I recommend?</h2><p>The panel said the right least-privilege setup depends on what the third-party tool actually needs to do.</p><p>For an analytics-oriented tool, the Sales role was suggested as the lowest-level role for the described use case. It gives access to sales-style data without allowing the kinds of changes the questioner was worried about.</p><p>If the tool needs to upload builds or use internal TestFlight, the Developer role may be appropriate. If the tool needs to manage product page metadata, in-app events, or similar marketing surfaces, the Marketer role may be appropriate.</p><p>The important correction is that this was not about a team choosing lower-permission roles for its own automation. The question was about users pasting their own App Store Connect API keys into a third-party tool. For that scenario, recommend the narrowest role that matches the tool&#8217;s purpose, and avoid asking for broader access than needed.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=3378s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can the App Store Connect API fetch live or last-24-hours sales and analytics data?</h2><p>Not today.</p><p>The panel confirmed that the last-24-hours view is available in the App Store Connect UI for Sales and Trends, but the API updates on a daily cadence. Through the API, developers can fetch daily, weekly, or monthly aggregates, but not the same live last-24-hours preview shown in the UI.</p><p>The data is the same kind of business data, but the cadence differs. If you need the latest view, use the UI. If you need automation, use the API reports with the available reporting cadence.</p><p>The panel clarified that this limitation is about analytics / sales-and-trends style data, not every piece of App Store Connect data.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=3470s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can I measure organic search traffic for a custom product page with its own custom keyword ranking?</h2><p>Not in the sense of a separate organic-search ranking for each custom product page.</p><p>The panel explained that custom product pages can be used with specific campaigns or links, and App Store Connect can show reporting for those pages. But organic App Store search is still centered around the main app listing and its search behavior.</p><p>So if you want to evaluate a custom product page, use its campaign links, product page analytics, and conversion data. If you want to understand organic search, use the main App Store analytics and search-related metrics.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=3546s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there a way to track phased release rollout progress for a new app version?</h2><p>Yes, App Store Connect shows phased release status in the UI.</p><p>The panel&#8217;s guidance was that phased release is managed through App Store Connect, and the UI shows where the version is in the rollout. Developers can also use their own app analytics, crash reports, and business metrics to decide whether to continue, pause, or stop a rollout.</p><p>For automation, the transcript did not describe a new dedicated API for live phased-release health. The practical workflow is to combine App Store Connect rollout state with the app&#8217;s quality and business signals.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=3627s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers help App Review test geospatial, AR, or location-dependent apps?</h2><p>Make the review path reproducible.</p><p>If the app depends on a physical location, route, geospatial anchor, AR state, or special account setup, explain that clearly in App Review notes. Include demo credentials, sample data, a test route, screenshots, or a video if needed.</p><p>The panel&#8217;s broader advice was to avoid making App Review guess how to reach important functionality. If a feature is hard to trigger from a desk, give reviewers enough context to understand and verify it.</p><p>This is especially important for location-heavy apps because the reviewer may not be in the relevant region or physical environment.</p><p><a href="https://www.youtube.com/watch?v=QPWPgSjg9Kc&amp;t=3683s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and asked practical App Store Connect questions throughout the session. Your questions made the discussion useful for developers working with App Store Connect APIs, TestFlight, App Review, subscriptions, retention messaging, analytics, product pages, API keys, universal purchase, localization, app visibility, and regional app strategy.</p><p>Question acknowledgments: Eorfy, Defabul, Claire KC, Brew Install Poppy, Stigler Farmers, Jonathan 8889, Lazy Var, Six Cups of Coffee, Hello Universe Help World C, Josh D, Alsant, Beloved Melody, Rustin 06, Jeff Bash, Lee Schwang Kuan, Artuk, Nachi, Jonathan A89, Justin from Baldwinville, and the online WWDC audience who submitted and upvoted the remaining App Store Connect questions.</p><p>Finally, a heartfelt thank-you to Laurel, Jeff, Lydia, Nick, Shi, Dave, and the App Store Connect teams behind the scenes for sharing practical guidance for launching apps, improving submissions, and growing app businesses.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: watchOS Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-watchos-group-lab-q-and-a</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-watchos-group-lab-q-and-a</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Wed, 17 Jun 2026 06:02:04 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f7779f3e-bc46-4847-adb1-c477de2b33f0_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This lab focused on watchOS 27, including Foundation Models, networking and background constraints, widgets, Live Activities, Smart Stack, HealthKit updates, Liquid Glass, SceneKit deprecation, debugging, app architecture, and standalone-watch behavior.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>Do Foundation Models on watchOS run on the connected iPhone, on Apple Watch, or through Private Cloud Compute?</h2><p>Foundation Models on watchOS do <strong>not</strong> require a connected iPhone, but they also do <strong>not</strong> run the model directly on Apple Watch.</p><p>The panel explained that requests go over the network. You can use Private Cloud Compute, or another provider that conforms to the <code>LanguageModel</code> protocol. Apple mentioned official support for Claude and Gemini coming from those vendors, and developers can also conform to the protocol themselves.</p><p>Because the watch is making a network call, developers need to think about availability, latency, quota, token use, and fallback behavior. If you use Private Cloud Compute, remember that it requires an entitlement.</p><p>Good watchOS use cases include summarizing dense text into something glanceable, making text more accessible for the small display, and generating useful insights from data in a way that still respects the watch form factor.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=281s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Does Foundation Models on Apple Watch use the on-device model from the paired iPhone if both devices are nearby?</h2><p>No.</p><p>The panel clarified that watchOS Foundation Models do not use the iPhone&#8217;s on-device model. The request goes over the network. That can be Private Cloud Compute or another <code>LanguageModel</code> provider, but it is still a network hop.</p><p>That means developers should design around latency and connectivity. Do not assume the watch can always get an immediate response, and do not assume the paired iPhone&#8217;s model will be used as a local fallback.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=653s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should iOS developers keep in mind when moving heavy background work, such as CloudKit syncing, to watchOS?</h2><p>Many familiar APIs exist on watchOS, but the constraints are stricter.</p><p>The panel mentioned that developers can bring over skills from iOS: <code>URLSession</code>, CloudKit, Swift async/await, and other familiar tools are available. But Apple Watch has tighter runtime, power, and thermal constraints.</p><p>The system enforces strict limits so that apps remain good citizens and preserve all-day battery life. If an app runs too long or does too much work in the background, it can hit watchdog timeouts.</p><p>The right architecture is to keep work focused, quick, and appropriate for the wrist. Reuse iOS knowledge, but do not assume the watch has the same runtime envelope, core count, or background budget as iPhone.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=723s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can an iPhone app have a useful Apple Watch presence without building a full watchOS app?</h2><p>Yes.</p><p>The panel highlighted Live Activities, notifications, widgets, Smart Stack, and controls as good entry points. You can bring parts of an iPhone app experience to Apple Watch without immediately building a complete watch app.</p><p>Live Activities from iPhone can appear on Apple Watch, and developers can customize the watch presentation if they want a better wrist-first experience. Controls can also appear in watchOS Control Center when they make sense for the watch.</p><p>This is a lightweight path for developers who are watchOS-curious. It lets users get glanceable, personal, wrist-appropriate experiences while the developer evaluates whether a full watch app is worth building.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=1070s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can developers speed up physical watchOS debugging loops and first-time symbol sync?</h2><p>Use the newest Xcode and watchOS tooling, stay close to the Mac, and make sure the network supports device-to-device communication.</p><p>The panel said Xcode has improved watch debugging substantially in recent releases, especially through Device Hub and a more direct Mac-to-Watch connection. In older workflows, communication often proxied through the iPhone. Newer workflows can connect more directly, improving reliability and throughput.</p><p>Network setup matters. Some corporate networks disable peer-to-peer communication, which can hurt debugging reliability. Newer Apple Watch hardware with 5 GHz Wi-Fi can also improve throughput.</p><p>The panel encouraged developers to try Xcode 27 and file feedback with logs if the debugging loop is still slow or unreliable, because Apple added diagnostics to help investigate remaining issues.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=1253s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the panel&#8217;s favorite new features in watchOS 27?</h2><p>Several favorites came up.</p><p>Workout Buddy and new workout insights were highlighted for providing personalized feedback over time, such as changes in cycling speed or other workout performance patterns.</p><p>Foundation Models on watchOS were another favorite, because they open up new possibilities for personalized, glanceable, intelligent wrist experiences.</p><p>The panel also called out updating widgets through Watch Connectivity. That means apps can keep widgets in sync between the iPhone app and Apple Watch companion experience more effectively.</p><p>Other favorites included Smart Stack suggestions, upcoming Siri AI work, and new HealthKit APIs such as heart-rate zones, cycling power zones, perimenopause and menopause APIs, and workout-zone data.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=1512s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should developers use for 3D graphics on watchOS now that SceneKit is deprecated and RealityKit is not available?</h2><p>SceneKit is deprecated on watchOS, but it is not gone yet.</p><p>The panel said developers can still use it for now, but the recommended direction is SwiftUI, especially SwiftUI Canvas, for graphics that fit the watch platform.</p><p>SwiftUI Canvas is GPU-backed and fast, and Apple sees it as more appropriate for many watchOS graphics experiences. It is not a full SceneKit replacement, but it is the modern path for many drawing and lightweight graphics use cases on the watch.</p><p>If you cannot achieve a specific effect with Canvas, Apple recommended talking to DTS, posting in the developer forums, or filing feedback so the team can understand what is missing.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=1738s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are some unique opportunities that Apple Watch offers beyond simply shrinking an iPhone app?</h2><p>Apple Watch is personal, glanceable, contextual, and sensor-rich.</p><p>The panel discussed using Core Motion data for wrist movement, which could support experiences such as motion-based interactions or even a watch acting as a peripheral in a broader multi-device experience.</p><p>Smart Stack and widget relevance also create opportunities to surface information at the right time. Developers can associate widget relevance with time, location, or semantic context such as being at home or work.</p><p>Live Activities can also be meaningful on watchOS, but they should be used carefully. Notify users only when the update is worth interrupting them; smaller status changes can remain passive.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=1852s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is new for Liquid Glass specifically on watchOS?</h2><p>watchOS 27 refines Liquid Glass with better legibility, contrast, separation, and performance.</p><p>The panel described updated dark edges and specular treatment, better separation as content scrolls, and performance improvements that make Liquid Glass feel better on the platform.</p><p>For many watchOS apps, developers do not need to do much manually. Apps already aligned with the watchOS 10 design language should get much of the Liquid Glass feel automatically.</p><p>Unlike iOS, watchOS does not provide a user-facing slider for glass clarity or tint. The panel said the watch&#8217;s mostly dark interface, smaller screen, and design constraints let Apple balance Liquid Glass and legibility without adding that setting. Accessibility options such as Reduce Transparency and Increase Contrast are still available.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=2353s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What hidden gems in watchOS 27 should developers know about?</h2><p>Two hidden gems stood out: workout zones and reorderable collections.</p><p>Workout zones, including heart-rate zones and cycling power zones, were described as long-requested APIs. They provide more than just zone boundaries; they can also support richer analysis such as time spent in zones and post-workout summaries.</p><p>The new SwiftUI reorderable API is also available on watchOS. Apple used it internally for Control Center, and developers can now build reorderable collections more easily in their own watch apps.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=2676s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Has the guidance changed for keeping watchOS widgets or complications up to date?</h2><p>The overall budget guidance remains roughly the same, but watchOS 27 adds useful improvements.</p><p>The panel discussed a developer question about whether approximately 50 widget or complication updates per day is still the right expectation. The answer was that developers should still treat updates as budgeted and avoid refreshing more than necessary.</p><p>What changed is that widgets can now be updated through Watch Connectivity, which gives developers a better way to keep watch widgets in sync with companion iPhone app data.</p><p>The advice remains to design timelines carefully, update only when the data actually changes, and use relevance to surface information at the right moment instead of trying to keep everything constantly refreshed.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=2863s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers think about Live Activities, notifications, and Smart Stack suggestions on Apple Watch?</h2><p>Use each channel for a different level of urgency.</p><p>Live Activities are great for ongoing, time-bounded experiences such as delivery tracking, sports scores, or something the user is actively waiting on. They should end when the activity is no longer relevant.</p><p>Notifications should be used for moments that deserve interruption. The sports example showed that &#8220;important&#8221; depends on the domain: basketball might alert at quarter boundaries, while soccer might alert on every goal.</p><p>Smart Stack suggestions can be softer. They can surface useful information without interrupting the user. The panel mentioned noise suggestions as an example of information that can appear before it becomes urgent enough for a notification.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=2054s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should a standalone watch app handle first launch if it needs to fetch a few hundred megabytes of assets?</h2><p>Do not assume the network will be available or fast on first launch.</p><p>The panel&#8217;s guidance was to design a graceful onboarding and fallback experience. Apple Watch can be independent, but connectivity can vary: the user may be on Wi-Fi, cellular, near an iPhone, away from an iPhone, or offline.</p><p>For a large asset download, avoid blocking the entire first-run experience if possible. Consider what minimal experience can work before the full asset set is available, and make the download state clear to the user.</p><p>Also think carefully about power, storage, and time. A few hundred megabytes is significant on a watch, so developers should fetch only what is necessary, resume downloads safely, and handle partial or failed downloads without leaving the app unusable.</p><p><a href="https://www.youtube.com/watch?v=DlVu0yBOphw&amp;t=3378s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and asked practical watchOS questions throughout the session. Your questions made the discussion useful for developers working with Foundation Models, Private Cloud Compute, networking, widgets, Live Activities, Smart Stack, HealthKit, workouts, Liquid Glass, SceneKit, debugging, standalone apps, and offline behavior.</p><p>Question acknowledgments: MRO, Durkio, Lazy Var, Pearl Jam 66, Zev Eisenberg, Pichaya Triys, Simon from Helix, Ashafrey, Medium Fidelity, and the online WWDC audience who submitted and upvoted the remaining watchOS questions.</p><p>Finally, a heartfelt thank-you to Leah Wlessdorf, Dan Keane, Ann Hitchcock, Devon, Matthew K., and the teams behind the scenes for sharing practical guidance about building great watchOS apps.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: Machine Learning & AI Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-machine-learning-and-ai-lab</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-machine-learning-and-ai-lab</guid><pubDate>Tue, 16 Jun 2026 12:03:04 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6ad83de6-3997-4db4-aea9-2700a1bc3e2f_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This lab focused on Core AI, Foundation Models, Private Cloud Compute, the Evaluations framework, MLX, local models, Xcode agent workflows, model conversion, availability, fallbacks, and when AI should or should not be part of the user experience.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>How should developers decide between on-device Foundation Models and Private Cloud Compute?</h2><p>Use evaluations, not guesses.</p><p>The panel explained the concrete differences first: the on-device model has a smaller context window and works offline, while the Private Cloud Compute model has a larger context window and supports reasoning. The server model can be a better fit for longer context or more complex reasoning tasks, but it depends on the feature.</p><p>The recommended workflow is to run comparative evaluations. Build the same feature against the on-device model and the Private Cloud Compute model, then evaluate both with the same data and metrics. Xcode&#8217;s evaluation reports can help compare runs side by side.</p><p>Latency should also be measured. On-device avoids network latency, but the panel noted that if network conditions are good, the round trip is not always the dominant cost. Instruments now exposes more Foundation Models metrics, such as round-trip latency, token budgets, and related performance data.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=400s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can Xcode use a local LLM through MLX or a custom model as an actual coding agent, not just chat?</h2><p>Yes, but the important part is the agent integration layer.</p><p>The panel distinguished between chat mode and the agentic / ACP path. If you want the model to do more than chat &#8212; for example, manipulate a project through Xcode&#8217;s tools &#8212; the agentic integration is the relevant path.</p><p>MLX can run a local model server, and Xcode can detect locally served MLX models in supported workflows. The panel also mentioned Xcode examples that use MLXLM server and open-code style integrations.</p><p>Core AI can run inference for a model, but it does not provide a ready-made server layer in the same way. To use Core AI in an agentic workflow, someone needs to provide the protocol conformance or an OpenAI-compatible language-server layer on top.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=1098s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should developers do if a local MLX model emits odd stop tokens or behaves strangely in Xcode agent mode?</h2><p>Check the model configuration and tokenizer first.</p><p>The panel said ending-token issues are common when bringing in new language models. If a model emits tags such as unexpected end markers, the likely areas to inspect are the tokenizer, model configuration, and chat template.</p><p>The team recommended posting details to the relevant GitHub repos or developer forums. The MLX language model and Core AI language model packages are open source, so issues can be debugged there with concrete configuration details.</p><p>The panel also noted that open-code-style workflows with MLX models do work in practice, so if behavior is strange, it is likely a configuration or template issue rather than a fundamental impossibility.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=675s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there a model version identifier so evaluations can detect when Apple&#8217;s models change?</h2><p>For the on-device model, use the OS version as the practical indicator.</p><p>The panel clarified that the on-device model is part of the OS and updates with OS updates. It is not silently swapped out independently of the OS.</p><p>For the server model, the situation is more complicated. The panel&#8217;s recommended defense is to treat evaluations as part of the workflow. When a new beta or OS release appears, rerun evaluation suites and compare results against previous runs.</p><p>They also advised against overly fragile prompt engineering that depends on exact wording for a specific OS point release. A better prompt should be robust enough to work across model updates where possible.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=1027s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can Foundation Models run from widgets, App Intents, or background tasks?</h2><p>Yes for the on-device model, but developers need to handle availability and rate limits.</p><p>The panel said the on-device model can run in the background and in widgets. However, on iOS the request may be rate-limited depending on system conditions. If the device is busy, hot, low on resources, or doing foreground work, the app may need to try again later.</p><p>Foreground user activity takes priority. If the user is playing a resource-intensive game, for example, background LLM work is less important than preserving that foreground experience.</p><p>macOS is different: the same background rate limiting does not apply in the same way. Still, quality-of-service and system scheduling should be respected.</p><p>The practical advice is to catch the specific error, avoid showing raw failures to users, and retry or degrade gracefully.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=1254s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can developers adapt models to their own app data or domain?</h2><p>Start with prompting and context before jumping to fine-tuning.</p><p>The panel suggested first using the app&#8217;s own data to build better prompts or in-context examples. Foundation Models can personalize behavior by taking relevant user-approved context as input without necessarily training a custom model.</p><p>If that is not enough, developers can bring in custom models, use MLX for training or fine-tuning, or convert and deploy models through Core AI. For image-generation-style use cases, the app may need a custom diffusion model or another specialized model rather than the Foundation Models framework alone.</p><p>The Evaluations framework can help with &#8220;hill climbing&#8221;: make a change to prompts, tools, model choice, or fine-tuning, then measure whether the output improved. Model-judge evaluators can also be used for qualitative outputs such as style or image quality when they are turned into measurable scores.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=1401s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What kinds of use cases are best suited to the Foundation Models framework, and what should developers avoid?</h2><p>Foundation Models are useful for language-heavy tasks such as content extraction, content generation, summarization, rewriting, classification, and multimodal reasoning with the new image input support.</p><p>They are not always the right tool for every machine-learning problem. If an app needs sub-millisecond decisions, real-time per-frame video analysis, ball tracking, or highly specialized speech / vision / translation behavior, Apple&#8217;s domain-specific frameworks may be a better fit.</p><p>The panel emphasized that Apple already provides high-level APIs for Vision, Speech, Translation, and other specialized tasks. Those APIs can be more optimized, support more languages or modes, and fit certain use cases better than prompting an LLM.</p><p>The practical rule: use Foundation Models when language reasoning is the core of the feature. Use specialized models or frameworks when the task is narrow, real-time, or already covered by a dedicated API.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=1846s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Where should beginners start if they want to learn AI and machine learning?</h2><p>Start with a small project and learn by building.</p><p>The panel recommended Swift Playgrounds and the older &#8220;Intro to ML&#8221; playground as a beginner-friendly path. That project used Core ML to build an image classifier for a rock-paper-scissors game and taught the basics of datasets and model use.</p><p>For Foundation Models specifically, Xcode now makes it easy to open a Playground and start with a <code>LanguageModelSession</code>and <code>respond</code> call. That gives beginners a fast path to experimenting with prompts and responses.</p><p>For deeper learning, the panel recommended starting from concrete examples, using online tutorials and courses, and letting tools or agents help explain unfamiliar concepts. Do not start with the math alone unless that is what motivates you. Build something first, then peel back the layers.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=2064s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can everything from PyTorch be imported into Core AI or the Apple ecosystem?</h2><p>Not everything, but many exportable models can be converted.</p><p>If a PyTorch model can be expressed through exportable PyTorch APIs and supported operations, Core AI conversion can be straightforward. When a model uses newer or custom operations, developers may need custom lowering, a custom op, or a custom Metal kernel.</p><p>For experimentation on Mac, MLX can be a comfortable path for people familiar with PyTorch. MLX APIs are similar enough that PyTorch users can often feel at home. Many Hugging Face models have already been converted for MLX, and MLX LM supports many models out of the box.</p><p>The panel also noted that AI coding agents can help translate model code between frameworks, author Core AI or MLX versions, and write custom kernels as a starting point.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=2350s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the best UX when Foundation Models are unavailable or slow to load?</h2><p>Check availability early, pre-warm when appropriate, and degrade gracefully.</p><p>The Foundation Models framework provides an availability API. Use it to detect cases such as unsupported devices, Apple Intelligence being disabled, or other availability reasons.</p><p>The on-device model also supports pre-warming. If the app knows that a model request is likely &#8212; for example, when a view appears and a model-powered button is visible &#8212; it can signal the system to load the model into memory ahead of time.</p><p>Fallback UX depends on the feature. Sometimes you can hide the model-powered button. Sometimes you can guide the user to enable Apple Intelligence. Sometimes you can use a server model or a custom model through the <code>LanguageModel</code>protocol. The key is not to expose raw technical failures as the primary user experience.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=2692s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When should developers avoid adding AI, even if it is technically possible?</h2><p>Use AI only when it adds clear value.</p><p>The panel&#8217;s guidance was that AI should not be added just because the technology is exciting. Some tasks are better handled by direct UI, deterministic rules, or specialized APIs.</p><p>If AI makes the experience slower, less predictable, harder to understand, or less trustworthy, it may be the wrong choice. Developers should evaluate whether the model meaningfully improves the user&#8217;s task.</p><p>The panel also emphasized privacy, latency, and user control. If the feature requires sensitive data, network calls, or non-deterministic behavior, make sure the benefit justifies the tradeoff and that the app communicates clearly.</p><p>The right use case is one where the model helps the user do something that would otherwise be tedious, difficult, personalized, or language-heavy.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=3332s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can developers provide their own <code>LanguageModel</code> implementation and still use Foundation Models features?</h2><p>Yes.</p><p>The panel highlighted the <code>LanguageModel</code> protocol as one of the most important new extensibility points. If a backend conforms to the protocol, it can participate in Foundation Models APIs even if the model is not Apple&#8217;s built-in on-device model or Private Cloud Compute model.</p><p>That means developers can connect MLX, Core AI, a third-party provider, or their own server-side model to the same higher-level programming model.</p><p>The panel noted that many utilities built on Foundation Models apply to any backend that conforms to the protocol. This makes it worth doing the integration work once, because it lets custom providers participate in the broader ecosystem.</p><p><a href="https://www.youtube.com/watch?v=n6TdbD7nh2k&amp;t=3633s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and asked practical Machine Learning and AI questions throughout the session. Your questions made the discussion useful for developers working with Core AI, Foundation Models, Private Cloud Compute, Evaluations, MLX, custom models, Xcode agent workflows, availability, fallbacks, model conversion, and local AI.</p><p>Question acknowledgments: Fantex, Pichaya, Dro Binin, Eric&#8217;s Questions, Ants Crashing, Natasha Prau, and the online WWDC audience who submitted and upvoted the remaining Machine Learning and AI questions.</p><p>Finally, a heartfelt thank-you to Shashank, Tao, Marcus, Michael, Louis, Ronan, and the teams behind the scenes for sharing practical guidance on building AI-powered apps across Apple platforms.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: Xcode Tips and Tricks Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-xcode-tips-and-tricks-group</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-xcode-tips-and-tricks-group</guid><pubDate>Tue, 16 Jun 2026 06:01:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/549b2da8-060a-4657-b603-a636d1ad0e76_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This lab focused on practical Xcode workflows: navigation, previews, project organization, build performance, debugging, source control, signing, Instruments, themes, Markdown, and everyday quality-of-life features.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>What are some useful Xcode tips and tricks that people often miss?</h2><p>The panel started with a round of personal favorite tips.</p><p>One highlighted feature was inline Swift playgrounds. You can import Playgrounds and use the <code>#Playground</code> macro inside any Swift file to run small snippets, inspect expression results, explore APIs, test models, and even preview UI from a standalone Swift file.</p><p>Another tip was workspace-specific themes. In Xcode 27, different workspaces can use different themes, which makes it easier to visually distinguish projects.</p><p>The team also called out a hidden file-creation trick: cut Swift code, focus the file navigator, and paste. Xcode creates a new Swift file from the clipboard and guesses the filename from the pasted type.</p><p>Other favorites included Find Call Hierarchy for refactoring, Command-Shift-J to reveal the current file in the navigator, and changing the debug app&#8217;s appearance so a debug build of Xcode is visually distinct from the Xcode instance being used to build it.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=195s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Which recent Xcode feature deserves more attention?</h2><p>Several features came up, but the biggest one was folder references, shown as blue folders in the navigator.</p><p>Unlike old gray groups, folders do not cause Xcode to record every individual file in the project file. That means adding or moving source files often creates no project-file diff at all. For large teams, this can dramatically reduce <code>.xcodeproj</code> merge conflicts.</p><p>Other features that deserve attention include scheme-level user defaults, console filtering by subsystem/category, searchable jump bar menus, preview variants with arguments, exporting memory graphs to Instruments, conditional breakpoints, and preview grids for combinations such as light mode, dark mode, or Dynamic Type sizes.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=443s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Why is the new &#8220;Delete Derived Data&#8221; menu item useful?</h2><p>It saves developers from manually deleting Derived Data folders or maintaining scripts.</p><p>The team acknowledged the gratitude from developers. There are real situations where deleting Derived Data helps: reclaiming disk space, starting a build from a clean state, or working around stale build state.</p><p>But they also cautioned that repeated need to delete Derived Data can hide a real project problem. If a clean state fixes the issue every time, investigate whether there is a missing dependency, a target-ordering issue, or a build graph problem.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=679s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can I install Xcode 27 beta while still using Xcode 26 to ship apps?</h2><p>Yes.</p><p>You can use Xcode 27 beta to explore new features while still using Xcode 26 to build and ship apps, as long as you avoid adopting SDK or project features that require the newer Xcode.</p><p>The team said Xcode 27 does not introduce broad project-file incompatibilities by default. There is a stricter project validation option, but it is opt-in and not something you are likely to enable accidentally.</p><p>If you use multiple Xcode versions, pay attention to <code>xcode-select</code> and which Xcode your command-line tools and CI are using. Xcode Cloud is also a good option for testing builds against different Xcode versions without relying on your local setup.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=765s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What underrated Xcode features should experienced developers use more?</h2><p>The panel again emphasized blue folders because they reduce project-file conflicts.</p><p>They also called out pinned preview tabs in the canvas. If you pin a preview tab, you can move around to other files while keeping the preview visible and updating.</p><p>Other underrated features included Xcode Cloud, powerful search in the search navigator, search combined with the bottom filter field, deleting individual search results from the find navigator to narrow a worklist, Command-clicking disclosure triangles to collapse sibling groups, Find Type Hierarchy, Instruments templates, flame graphs, top functions, the SwiftUI instrument, and the ability to save custom Instruments templates.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=868s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What caveats should I know about running Xcode 27 beta and Xcode 26 on the same machine?</h2><p>The panel said this is supported.</p><p>Apple engineers themselves regularly use multiple versions of Xcode and macOS while developing. The main caveat is project compatibility: avoid adopting new project or SDK features if you still need to open and ship from the older version.</p><p>For Xcode 27 specifically, the panel did not identify major project-file caveats. The strongest practical reminder was to keep track of which Xcode version is selected for local command-line tools and CI.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=1204s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can teams reduce painful <code>.xcodeproj</code> merge conflicts without third-party project generators?</h2><p>Convert old gray groups to blue folders.</p><p>Blue folders represent actual folders and are target members. Xcode does not need to list every source file individually in the project file, which means fewer diffs and fewer conflicts.</p><p>To migrate safely, right-click a group and choose Convert to Folder. If you hold Option, Xcode preflights the operation and tells you what must be resolved before migration. Resolve errors first, commit that cleanup, and then do the migration in a separate step.</p><p>Also check the project inspector for the setting that minimizes cross-project references if you work with multiple Xcode projects.</p><p>For build settings, consider <code>.xcconfig</code> files. They make settings easier to review in pull requests, easier to comment, and less likely to produce noisy project-file diffs. In the build settings editor, the help inspector can show the underlying build setting key, and you can copy build setting rows into config files.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=1264s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the useful Markdown tricks in Xcode 27?</h2><p>Xcode 27 has a proper rendered Markdown experience.</p><p>You can view Markdown as rendered content or open it as source code. Both forms are editable. You can also use the canvas preview button to see rendered Markdown side-by-side with the source.</p><p>This applies both to standalone Markdown files and Markdown generated or edited as part of agent workflows, such as plans or documentation files.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=1497s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Were there source-control improvements in Xcode 27?</h2><p>The team mentioned infrastructure and performance work rather than one large visible source-control feature.</p><p>The source-control navigator was rebuilt internally while keeping the same user-facing behavior. Repository performance is also better in cases with very large numbers of tags.</p><p>There was also a small visual update: diffs now use red and green by default. If you prefer other colors, theme customization lets you change them.</p><p>The panel also acknowledged a feature request for multi-select stash deletion and said they would bring it back to the team.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=1560s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can macro trust for Swift packages be pinned to a package identity instead of requiring reapproval after every package update?</h2><p>The panel did not have the Swift Package Manager experts in the room, so they did not give a definitive answer.</p><p>They were surprised by the report that trust was invalidated on every update and recommended filing Feedback Assistant with the specific package and reproduction details.</p><p>The key action item: if macro approval is breaking CI or blocking builds after package updates, file feedback with the package name, update path, Xcode version, and exact failure mode.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=1664s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there a way to open Terminal at the project root from Xcode?</h2><p>Not directly today.</p><p>One workaround is to open Terminal and drag a file or folder reference from Xcode into Terminal to get the path.</p><p>A related Xcode 27 improvement is that the file inspector now shows a working-copy-relative path. You can copy that path and use it in Terminal for Git or other command-line operations.</p><p>The panel said opening Terminal directly at the project root is good feedback to file, especially because Xcode already has similar &#8220;Show in Finder&#8221; workflows.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=1733s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the most useful Xcode keyboard shortcuts?</h2><p>The panel mentioned several daily shortcuts.</p><p>Command-Shift-J reveals the current file in the project navigator. Command-Shift-Y shows or hides the debug area. Control-Option-Command-G reruns the last test. Command-Option-P refreshes previews. Control-6 opens the symbol menu for the current file and lets you filter within it.</p><p>Command-Option-Up and Command-Option-Down switch between Objective-C header and implementation. Command-Shift-O opens Open Quickly. Command-Control-R launches without building. Command-I profiles. Control-Backslash jumps to the next diff. Command-Slash toggles comments.</p><p>Xcode settings contains a searchable key bindings table where you can inspect and customize shortcuts.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=1794s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are common beginner mistakes in Xcode, and how do you avoid them?</h2><p>Do not try to learn every Xcode feature at once.</p><p>Start with the essentials: source editor, navigator, inspectors, build/run/test, previews, and debugging. You can grow into the rest of the tool over time.</p><p>The panel strongly recommended automatic signing for most developers. Manual signing can be powerful, but it is easy to get stuck as a beginner.</p><p>They also strongly recommended using Git, even for solo projects. Source control is the best undo system you have.</p><p>For performance work, profile on a real device, not the simulator. Also profile release-style optimized builds rather than debug builds, or you may chase performance problems that do not exist in production.</p><p>When starting new projects, use modern defaults: SwiftUI, Swift concurrency, and source control. Organize files early, use folders, and let agents help with restructuring if one file grows too large.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=2004s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is an efficient workflow for generating and maintaining DocC documentation during active development?</h2><p>Use documentation previews and keep documentation close to the source.</p><p>Xcode can preview DocC documentation generated from comments in your source files. You can also host a DocC archive as a static website for pull-request review.</p><p>The panel also warned that agents may over-document or expose implementation details in comments. Generated documentation still needs human review.</p><p>DocC is open source, so developers can inspect the implementation and learn from previous WWDC sessions and developer documentation.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=2390s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Which settings or practices can significantly improve build time?</h2><p>Focus first on incremental build performance.</p><p>Run without building when you do not need a rebuild. Command-Control-R launches again without rebuilding.</p><p>Split code into modules such as packages or frameworks so changes in one part of the project do not invalidate everything else. Use the build timeline assistant in the build log to understand what rebuilt and why.</p><p>You can also opt into Swift compiler warnings for expressions that take too long to type-check, then simplify those expressions.</p><p>Be careful with script phases. If a script phase has no declared inputs and outputs, it may run too often and invalidate build products. Declare inputs and outputs so Xcode can run scripts only when needed.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=2522s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can I make Xcode previews load faster?</h2><p>Treat preview performance like build performance.</p><p>The panel recommended keeping the preview&#8217;s dependency graph small. If the preview depends on a lot of unrelated code, every change can invalidate too much work.</p><p>Use smaller, focused previews where possible. Prefer preview data and lightweight fixtures instead of bootstrapping the whole app environment.</p><p>Also avoid forcing the preview to wait on slow setup work that is not relevant to the UI being previewed. If a preview can be isolated from networking, persistence, or heavyweight services, it will usually be faster and more reliable.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=2703s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can breakpoints do more than just stop execution?</h2><p>Yes.</p><p>Breakpoints can have actions and conditions. You can make a breakpoint log something, play a sound, run an LLDB command, or trigger only after a condition is true or after it has been hit a certain number of times.</p><p>This is useful when print debugging would be noisy or when you want to observe behavior without stopping the program every time.</p><p>The panel highlighted conditional breakpoints earlier as a favorite underused Xcode feature.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=2867s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can I find unused variables, functions, or stale code in a project?</h2><p>Use a mix of compiler help, search, refactoring tools, and agent-assisted cleanup.</p><p>The compiler can catch some unused variables and unreachable code, but not every kind of stale function or unused abstraction.</p><p>Search tools can help identify call sites, and Find Call Hierarchy or Find Type Hierarchy can show whether functions, protocols, or types are still connected to the rest of the project.</p><p>For broader cleanup, the panel suggested agents can help. Ask the agent to inspect usage, produce a plan, and then validate the result with builds and tests before deleting anything.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=3059s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is deleting Derived Data useful, or is it just superstition?</h2><p>It can be both.</p><p>Deleting Derived Data is sometimes genuinely useful: it gives you a clean build state, frees disk space, and clears stale intermediate products.</p><p>But if you need to delete Derived Data repeatedly to fix the same problem, that is a signal to investigate the project. There may be a missing dependency, a script phase issue, or another build graph problem.</p><p>The new menu item makes the workflow easier, but it should not replace diagnosing recurring build failures.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=3157s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should I know about Claude Code context compression and project instructions such as <code>CLAUDE.md</code>?</h2><p>Context compression is a normal part of long-running agent work.</p><p>When an agent&#8217;s context grows too large, it may summarize or compress earlier information so it can keep working. That can be useful, but details may be lost or distorted.</p><p>Project instruction files such as <code>CLAUDE.md</code> can help keep the agent aligned with your conventions, architecture, and expectations across turns. Use them for persistent guidance: coding style, testing expectations, architecture notes, and rules the agent should follow.</p><p>The panel&#8217;s general advice was to make expectations explicit and keep important project knowledge in files the agent can read, instead of relying on one long chat history.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=3417s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How do signing and provisioning issues affect profiling with Instruments?</h2><p>Signing still matters when profiling.</p><p>If Instruments cannot launch or attach correctly, or if profiling behaves differently from running normally in Xcode, check signing and provisioning first. Make sure the app is signed with the right team, entitlements, and provisioning profile for the device and workflow.</p><p>The panel&#8217;s broader advice was to prefer automatic signing unless you have a specific reason to manage signing manually. Manual signing gives control, but it also makes it easier to get stuck with mismatched profiles or entitlements.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=3529s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Are there better ways to fold code or navigate structure in large files?</h2><p>Yes &#8212; use structural navigation tools before relying only on manual folding.</p><p>The panel pointed to Control-6 as a useful shortcut: it opens the symbol menu for the current file, and you can type to filter within it. That gives you a file-scoped &#8220;open quickly&#8221; style workflow for jumping between functions, types, and other symbols.</p><p>Open Quickly is still useful for broader project navigation, and hierarchy tools can help when you need to understand relationships rather than just scroll around. Find Call Hierarchy helps trace who calls a function, and Find Type Hierarchy helps inspect protocol conformances and subtype trees.</p><p>For folding itself, Xcode can fold structural regions, but if you constantly need folding to survive a file, that is often a sign the file should be split into smaller, focused source files.</p><p><a href="https://www.youtube.com/watch?v=ygSPAu7JMWQ&amp;t=3669s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared practical Xcode workflow questions throughout the session. Your questions made the discussion useful for developers working with previews, playgrounds, themes, folders, project conflicts, Derived Data, source control, Markdown, signing, profiling, build performance, debugging, keyboard shortcuts, structural navigation, and agent-assisted workflows.</p><p>Question acknowledgments: Paya, Fantex, Franklin Bu, Formidable Studio, Scott G, Newbie, Tammy Santana, Conto, Chrissia, Claire KC, Protonster, Theo K, Pza, and the online WWDC audience who submitted and upvoted the remaining Xcode Tips and Tricks questions.</p><p>Finally, a heartfelt thank-you to Angelica, Chris Miles, Jake, John, Katper, Chris, and the teams behind the scenes for sharing so many practical Xcode tips.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: Coding Intelligence for Beginners Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-coding-intelligence-for-beginners</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-coding-intelligence-for-beginners</guid><pubDate>Mon, 15 Jun 2026 12:03:47 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c95bfef8-6a23-4509-b995-96eb9ca808bc_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Coding intelligence changes the way developers move from idea to implementation. The panel framed agents as a way to explore ideas faster, validate work with builds and tests, and keep developers in control while offloading repetitive or exploratory work.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>How has app development changed with coding agents?</h2><p>Agents make it easier to turn rough ideas into something concrete.</p><p>The panel described a workflow where developers can ask an agent to help create a spec, iterate on that spec, and then use it as a shared description of the feature being built. That makes intent more explicit than it often was in older workflows.</p><p>Agents also reduce the cost of trying ideas. If a path looks expensive, you can ask the agent to explore it, generate a prototype, validate it, and even discard it if it is not right.</p><p>The biggest shift is not just faster code generation. It is that agents can verify their own work with builds, tests, previews, and other tools, which lets developers spend more time on creativity, product direction, and judgment.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=219s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Where is the best place to learn slash commands like <code>/plan</code>?</h2><p>Type <code>/</code> in Xcode&#8217;s coding intelligence interface.</p><p>Xcode can show compatible slash commands that the current agent provides, along with Xcode-provided skills. You can also ask the agent directly what commands it supports and what each command does.</p><p>The panel&#8217;s practical advice was to experiment. Try the commands, ask the agent what workflows are available, and see what each one changes in your process.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=441s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What unique advantage does Xcode&#8217;s built-in coding intelligence provide over external AI agents?</h2><p>Xcode has Apple-platform context that generic external agents do not automatically have.</p><p>The panel highlighted several areas: project understanding, SDK and documentation awareness, Apple-platform best practices, and direct access to Xcode tools for build, validation, previews, UI rendering, and interaction.</p><p>Xcode can also expose Apple ecosystem data and workflows such as crash information, localization guidance, and platform-specific validation. The preview system is especially important because it lets the agent inspect and reason about UI, not just text.</p><p>Another advantage is onboarding. Xcode provides a strong default setup: planning mode, useful built-in tools, good base guidance, and an extensible plugin story. That gives beginners a running start while still supporting advanced workflows.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=503s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Does Xcode 27 show how many agentic resources are being consumed while a request is running?</h2><p>Not directly in the Xcode UI.</p><p>The panel said that most agent providers expose slash commands for this. One command usually reports the current state of the main context window, while another reports usage or cost so far.</p><p>Those are different numbers. Context-window fullness tells you whether the agent is getting close to compressing or summarizing context. Usage or cost tells you something closer to what you have consumed financially or against a quota.</p><p>If developers want this surfaced directly in the Xcode UI, the panel recommended filing feedback with the desired placement and use case.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=754s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can the Xcode AI agent read or search implementations from other local projects?</h2><p>Yes, but access is controlled.</p><p>If the other project is part of the same Xcode workspace, Xcode can naturally expose that context to the agent. Workspaces are the recommended way to bring multiple projects together when they are part of the current task.</p><p>For files outside the workspace, you can provide paths or references and grant access as needed. Xcode uses permission prompts by default so the agent gets what it needs without having unrestricted access to everything.</p><p>There is also a managed security mode in Xcode settings, described as an early preview, that can gate agent actions at the file-system level.</p><p>The important principle is that the developer remains in control. The agent can request access, but you decide what it can read, move, copy, delete, or modify.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=845s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How can beginners understand code that an agent wrote for them?</h2><p>Ask the agent to explain its work.</p><p>The panel suggested several practical workflows: ask &#8220;why did you do that?&#8221;, request a Markdown or HTML report, ask for a summary after each completed task, or configure an <code>AGENTS.md</code> file so the agent always explains its changes in a format you prefer.</p><p>Plan mode is also useful because it lets you understand the proposed approach before code is changed. You can review the implementation plan, challenge assumptions, and guide the agent before it writes a lot of code.</p><p>Another strategy is to give the agent partial structure: define the protocol, type names, properties, or comments that describe intent, then let the agent fill in the implementation. That keeps you closer to the architecture while still getting help with details.</p><p>For learning, agents can also generate diagrams, architecture documents, quizzes, or explanations tailored to how you learn.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=1037s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What common mistakes do coding assistants make that beginners may not catch?</h2><p>Agents can misunderstand your assumptions.</p><p>Sometimes they produce something that works but is not maintainable. Sometimes they miss context. Sometimes they take shortcuts that appear to finish the task but do not actually satisfy the intent.</p><p>The panel called out &#8220;cheating&#8221; as a subtle failure mode: an agent might rationalize away a failing test, claim something only fails because of a debug configuration, or otherwise explain why incomplete work is acceptable. If you would not accept that explanation from a coworker, do not accept it from the agent.</p><p>Validation helps. Strong types, compiler errors, tests, previews, live issues, and build tools give the agent fast feedback before it hands the work back to you.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=1392s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there a way to undo everything an agent changed?</h2><p>Yes, but the best workflow depends on your project setup.</p><p>You can ask the agent to undo its work or return to the previous state. Agents usually understand their own recent changes well enough to revert them.</p><p>Xcode also tracks history across turns when the project has a Git repository initialized. You can open the history view, move back one turn, and revert to the state before the agent&#8217;s last action.</p><p>The panel strongly recommended using Git even for solo projects. Git is not only for teams. It gives you a safety net, a way to recover from mistakes, and useful history that agents can also use to understand why changes were made.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=1588s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should an experienced iOS developer with little AI-coding-assistant experience build the skills expected by modern engineering roles?</h2><p>Start small and bring your existing experience with you.</p><p>The panel recommended using agents on tasks you already know how to do: small bugs, small features, or low-risk refactors. That lets you compare the agent&#8217;s output against your own expectations and build confidence.</p><p>As an experienced developer, your judgment is valuable. You can guide the architecture, identify bad assumptions, review generated code, and teach the agent your preferences.</p><p>You do not need to hand over all control. You can use agents for planning, exploration, documentation, code search, or architecture review before letting them implement anything.</p><p>The recommended session for more workflow ideas was &#8220;Xcode agents and you.&#8221;</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=1861s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the key differences between agent mode and chat mode?</h2><p>The difference is capability and scope.</p><p>Chat mode has access to a smaller set of tools and is better suited to shorter interactions: asking questions, making limited code changes, or getting help with a specific issue.</p><p>Agent mode can use a much larger toolset. The panel described it as effectively open-ended: command-line tools, many Xcode tools, context management, subagents, and longer-running work.</p><p>Agents can work for much longer time horizons than chat. Chat may answer or edit within seconds. Agents can plan, execute, validate, fix errors, and continue working for much longer tasks.</p><p>The panel encouraged developers to move from chat to agents in Xcode 27 because agents can still do small tasks, but they also unlock bigger workflows.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=2171s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can local models provide the same Xcode coding intelligence features as cloud models?</h2><p>It depends on whether you are talking about the model or the agent wrapper.</p><p>Xcode can talk to local models, including models running on your Mac or on a local server. In chat mode, a local model gives you the chat experience.</p><p>For agentic workflows, you need an agent that can talk to that local model. With ACP support, local or open-source agents can use the same Xcode toolset that cloud-backed agents use.</p><p>The biggest difference is model capability. A huge commercial model running on a specialized GPU cluster may reason better than a smaller local model on a laptop. But local models can still be very useful, especially if you give them strong guardrails and good validation loops.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=2397s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can I connect Xcode coding intelligence to a local LLM like one hosted by <code>mlx_lm.server</code> in agent mode?</h2><p>Yes, but approach it through a local agent rather than only chat mode.</p><p>The panel pointed to ACP support as the path for this. Open-source tools and wrappers with local model support can act as the agent layer, while the local model provides the inference backend.</p><p>The session &#8220;Run local agentic AI on Mac using MLX&#8221; was recommended as a good starting point for this workflow.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=2550s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What happens to my code when it is accessed by a third-party LLM through Xcode?</h2><p>Apple does not see those requests.</p><p>When you configure a third-party coding agent or model provider, the request goes directly to that provider. You need to read that provider&#8217;s terms, privacy policy, and account settings to understand whether your code or prompts can be stored, retained, or used for training.</p><p>The panel emphasized that developers are in control of choosing providers and provider settings. If you send code through Feedback Assistant, Apple can see what you intentionally included in the feedback report, but normal coding-agent requests go to the selected provider, not to Apple.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=2598s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the best way to work with AI in Xcode while offline, such as on a train commute, without a huge Mac?</h2><p>Use local models and local agents for offline work, and plan ahead when you can.</p><p>The panel suggested a hybrid workflow: use a larger cloud model before you go offline to help plan the work, write requirements, and set up assumptions. Then, while offline, use local agents and local models to implement or continue the work.</p><p>Have the local agent write down assumptions and decisions in Markdown files. When you are back online, ask a larger model to review those assumptions and check whether they still make sense.</p><p>Xcode also makes it possible to configure multiple agents and models, then switch between local and cloud-backed workflows depending on whether you are online.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=2730s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>If I already use Claude Code in Terminal and barely open Xcode, what am I missing?</h2><p>You may be missing the Xcode-specific experience layer and tools.</p><p>Terminal workflows are powerful, but they are mostly linear text streams. Xcode can provide a richer nonlinear UI around agent work: code editing, previews, build results, issue navigation, diffs, history, project context, and platform-specific validation.</p><p>Xcode also exposes Apple-platform tools and context to the agent. That includes previews, Xcode build and validation tools, project understanding, and integration with the IDE experience you already use to ship Apple-platform apps.</p><p>The point is not that terminal agents are bad. It is that Xcode can combine agentic coding with the Apple development environment, which matters when building apps for Apple platforms.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=2886s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is it possible to use local AI models for coding intelligence with Xcode 27?</h2><p>Yes.</p><p>The panel pointed developers to the &#8220;Run local agentic AI on the Mac using MLX&#8221; session as the best place to start. Local models can run on your own Mac or local hardware, and with the right local agent setup they can participate in Xcode&#8217;s agent workflows rather than only simple chat.</p><p>The key distinction is that the local model is just one part of the system. To get agentic behavior, you need an agent wrapper or integration that can use the model and connect to Xcode&#8217;s toolset. With ACP support, local or open-source agents can still access the same Xcode-provided tools.</p><p>This is especially useful if privacy, offline work, or local experimentation matters to you. The tradeoff is that smaller local models may need more guardrails, stronger validation, and clearer prompts than large cloud-hosted frontier models.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=3070s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there a way to use Apple foundation models as the agent for Xcode coding intelligence instead of Anthropic, OpenAI, or Google?</h2><p>The panel pointed back to the local agent and local model story.</p><p>If the goal is to avoid third-party cloud providers for privacy reasons, use local models and local agents. The recommended starting point was the session about running local agentic AI on Mac using MLX.</p><p>The Mac is a strong platform for this. Even a single modern Mac can run useful local workflows, and more powerful Mac hardware can run larger models.</p><p><a href="https://www.youtube.com/watch?v=Vd5nu5qIhGk&amp;t=3260s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and asked practical questions about agentic workflows, slash commands, Xcode context, local models, privacy, undo, Git, validation, learning with agents, chat versus agent mode, and offline development.</p><p>Question acknowledgments: Pichaya Triys, Jason Chung, Harry 3, Juto Art, Tammy Santana, Florentine F, UJ, Interferon, Ants Crashing, Stuff MC, Jay Rooden, Ron Learns, and the online WWDC audience who submitted and upvoted the remaining Coding Intelligence for Beginners questions.</p><p>Finally, a heartfelt thank-you to Angelica, Nathan, Ken, Jerome, Kevin, and the teams behind the scenes for explaining how beginners and experienced developers can get started with coding intelligence in Xcode.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[
WWDC26: Privacy and Security Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-privacy-and-security-group</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-privacy-and-security-group</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Mon, 15 Jun 2026 06:02:01 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/80ca894e-60af-4a45-86b9-18749fe84264_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Privacy and security are not one feature you add at the end. They shape authentication, cloud processing, AI agents, telemetry, App Store privacy labels, app architecture, platform APIs, and how clearly you explain your app&#8217;s behavior to users.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>How is Apple ensuring that models are not hijacked through prompt injection techniques?</h2><p>Prompt injection becomes especially important with agentic systems because a model may have access to private data, the ability to perform actions, and untrusted context.</p><p>The panel called out indirect prompt injection as a specific risk. In that attack, a malicious document, message, or other piece of content enters the model&#8217;s context and tries to make the model do something the user did not intend.</p><p>Apple treats this as a new class of security and privacy risk. For features such as Siri AI and other agentic experiences, the teams design mitigations before the feature ships.</p><p>Those mitigations include deterministic approaches, such as confirmation prompts where the user explicitly approves an action, and probabilistic approaches, such as spotlighting parts of a prompt so the model can distinguish trusted instructions from untrusted content.</p><p>The practical developer lesson is to think carefully about the &#8220;lethal trifecta&#8221;: private data, actions, and untrusted context. If your agentic feature combines all three, you need a strong security design.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=320s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When my app sends user data to Private Cloud Compute or to a third-party model like Anthropic or Google through the new language model protocol, what actually happens to that data and what do I need to tell my users?</h2><p>Private Cloud Compute and third-party AI APIs are different cases.</p><p>When you use Apple&#8217;s Private Cloud Compute through Apple APIs, Apple&#8217;s PCC guarantees apply. The panel highlighted stateless computation, non-targetability, enforceable guarantees, cryptographic proof, and public documentation and tooling that developers or security researchers can use to verify Apple&#8217;s claims.</p><p>Data sent to PCC is used only to fulfill the request. It is not available for Apple or anyone else to inspect, and the node removes the data after the request. If the node reboots, the persistent volume that could hold data is wiped clean.</p><p>For third-party APIs, Apple&#8217;s PCC guarantees do not apply. If you send user data to Anthropic, Google, or another provider, you need to read that provider&#8217;s terms and documentation, understand what they do with the data, and explain that clearly to users.</p><p>The practical rule is simple: if data leaves your app through a third-party service, you are responsible for understanding and communicating that service&#8217;s data handling.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=451s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What distinction does Apple draw between data I collect versus data a third-party processor handles on my behalf? If my voice and photo features send data to outside services purely for processing, does that count as my collection, theirs, both, or something else?</h2><p>For App Store privacy labels, you are responsible for declaring data collected from your app, whether it goes to your own servers or to another company&#8217;s service.</p><p>That means a third-party processor does not automatically remove your responsibility. You still need to understand what data leaves the app, whether it is linked to the user, what purpose it is used for, and what the third party does with it.</p><p>The point of the privacy label is to give users the full picture of your app&#8217;s privacy practices. If the user&#8217;s voice or photo data is sent to an outside service, even only for processing, that relationship needs to be understood and represented accurately.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=639s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>AI models do not always do what you expect. What security risks are there when using the new agentic coding features in Xcode, and what are the best practices to mitigate them?</h2><p>The same broad agentic-security concerns apply: untrusted context, private data, and actions. Xcode adds another dimension because agents may interact with tools, source code, project files, build systems, and the developer&#8217;s local environment.</p><p>Apple designs these features with a secure-by-design approach. The panel mentioned additional mitigations around Xcode, including allow-listing common tools when Xcode is used as an MCP server.</p><p>The best practice is to treat agentic coding tools as powerful assistants, not fully trusted actors. Be deliberate about which tools the agent can call, which files it can access, and which actions require human approval.</p><p>Review code changes and understand generated behavior before committing or shipping. Agentic coding can accelerate development, but it does not remove the need for code review and security thinking.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=713s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the core architecture behind Private Cloud Compute for cloud AI processing in privacy-sensitive apps? How does Apple mathematically ensure no one can see this data, and how do we verify there are no hidden flaws?</h2><p>The panel pointed developers to Apple&#8217;s in-depth Private Cloud Compute security guide for the full technical explanation.</p><p>At a high level, PCC is built around stateless compute, verifiable privacy, transparency, and enforceable guarantees. Apple publishes documentation and tooling so researchers can independently verify that deployed PCC software matches the public guarantees.</p><p>PCC also uses attestation. The discussion called out additional security layers in the Google Cloud PCC deployment, including requiring two verifiable attestations for hardware from two separate vendors.</p><p>Apple also isolates complex parsing work, such as image parsing, into separately sandboxed nodes where needed. This may add latency, but it reduces risk when processing complex data formats.</p><p>The larger point is that Apple is not asking developers or users to simply trust the cloud. PCC is designed so claims about software, node identity, and data handling can be checked continuously. If rogue software were deployed to a node, attestation would change and devices would reject it.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=792s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Are there new ways to audit my own app to ensure user data remains private and secure, especially if I use SwiftData with CloudKit?</h2><p>The panel framed this as a mix of tooling, architecture, and developer responsibility.</p><p>Generative AI and coding agents can help you review your app&#8217;s privacy and security assumptions. You can describe what your app promises, what data it handles, and where that data flows, then use the model as one tool to look for gaps.</p><p>Apple also provides platform APIs that are secure and private by default where possible. CloudKit is a good example: it lets you sync user data across a user&#8217;s devices without running your own server, which can reduce the amount of infrastructure risk you take on.</p><p>But you still need to reason about your app. For security, start by asking what inputs enter the app and how much you trust them. For privacy, ask what user data you collect, where it goes, and who you vend it to.</p><p>The panel&#8217;s reminder was direct: developers are partly responsible for the privacy and security of the people who use their apps. Use platform-native tools, but do not stop thinking critically about data flows.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=1176s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>If I am starting my journey developing apps for Apple platforms, which privacy and security tools or frameworks should I focus on first?</h2><p>Start with the platform frameworks that reduce how much sensitive work you need to build yourself.</p><p>For account security, adopt passkeys instead of passwords when you can. Passkeys reduce phishing risk, simplify sign-in, and remove a lot of password-reset friction.</p><p>For secrets and credentials, use Keychain and choose the right data protection class. For cryptographic work, use CryptoKit instead of inventing your own crypto. For cloud sync, use CloudKit where it fits, because Apple handles much of the secure synchronization work for you.</p><p>For privacy, practice data minimization. Ask whether you need the data at all. If you only need a photo, contact, file, or location once, consider an out-of-process picker or a more limited permission rather than asking for broad access.</p><p>For telemetry, start with the question you actually need answered. If a metric will not lead to a product or code decision, do not collect it. Use the least identifying identifier that works: a session identifier may be better than a device identifier, and many cases should not need a real user identity at all.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=1487s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>If a user stores highly personal journal entries, readings, or history in SwiftData, what are Apple&#8217;s recommended approaches for protecting that data while still enabling search and synchronization?</h2><p>Use the strongest protection that still allows the app experience to work.</p><p>For local data, use data protection classes. For very sensitive data, the panel suggested protection that is only available when the device is unlocked, and for keys in Keychain you can require biometric unlock where appropriate.</p><p>For CloudKit, use encrypted values so sensitive data remains protected when synchronized across a user&#8217;s devices. For users with Advanced Data Protection enabled, CloudKit encrypted values can be end-to-end encrypted.</p><p>Search and indexing require a careful tradeoff. If content needs to be indexed after the device locks, use the right data protection class for that requirement. The panel mentioned classes that keep data available for a limited time after locking, allowing background indexing to complete before the key becomes unavailable.</p><p>The practical model is to separate what must be highly protected from what must remain searchable, and to choose data protection classes and CloudKit encryption deliberately instead of storing everything at the same level.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=1836s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>With Xcode AI coding features, can Xcode be run inside a virtual machine on an air-gapped Mac walled off from the internet to improve security and privacy?</h2><p>It depends on which feature you are using.</p><p>Existing code-completion features can run entirely on device and work offline.</p><p>Other features that integrate with cloud-based coding systems, such as Claude Code or OpenAI Codex-style integrations, require internet access. Those cannot work in a fully air-gapped environment because the request needs to leave the device.</p><p>The short version: local completion can work offline; cloud-backed agentic coding features need the network.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=2034s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How does the new Siri AI ensure privacy and security, especially avoiding sharing private context with apps?</h2><p>Siri AI uses several layers of protection.</p><p>Some work happens on device. When larger models are needed, Siri can use Private Cloud Compute, which brings the PCC guarantees discussed earlier: stateless computation, attestation, enforceable guarantees, and data used only to fulfill the request.</p><p>On device, Apple uses platform technologies such as sandboxing, entitlements, and controlled system daemons to gather and process the context needed for Siri. Not every process can access that user data.</p><p>When third-party apps are involved, data is minimized. Siri does not simply hand over extra private context to an app. It shares what is needed for the user-directed action.</p><p>User consent systems still matter. If Siri needs access to protected categories such as location, the same kinds of privacy controls and prompts apply.</p><p>The panel also emphasized Apple silicon as a privacy technology: more local compute means more work can stay on device, inside the platform&#8217;s security boundaries.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=2094s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is TCC?</h2><p>TCC stands for transparency, consent, and control.</p><p>It refers to the protections that let apps request access to protected user data such as photos, microphone, camera, contacts, location, and similar categories.</p><p>The point is that users can see what an app is asking for, decide whether to grant access, and retain control. If an app has not asked for microphone access and the user has not granted it, the app should not be able to access microphone data.</p><p>TCC is one of the core privacy systems developers interact with when building apps for Apple platforms.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=2349s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Will Siri AI have a configurable policy in MDM when released?</h2><p>Yes.</p><p>The panel said existing MDM controls for Siri should still apply. Enterprises should think carefully about which parts of Siri AI they want to allow or restrict in their environments.</p><p>If an enterprise has specific policy needs, the recommendation was to file feedback. Apple wants to understand how organizations want to configure these tools, especially when some features may be useful while others need stricter control.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=2412s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Are there new enhancements to Safari ITP tracking prevention in the new operating systems?</h2><p>The panel did not announce a specific new ITP feature in this lab.</p><p>They emphasized that Intelligent Tracking Prevention continues to be an area Apple invests in over time. It has evolved for years and remains an important privacy technology.</p><p>For technical details and updates, the panel pointed developers to WebKit resources such as <a href="http://webkit.org/">webkit.org</a>.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=2478s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How do you effectively convey to users that your app is secure and privacy preserving without sounding like snake oil, security theater, or unverifiable marketing?</h2><p>Make trust observable.</p><p>App Store privacy labels are one place to start because they create a standardized way for users to compare privacy practices before downloading an app.</p><p>Inside the app, be transparent about what data you have and why. If you collect or process user data, do not hide that fact. Give users a way to understand and control it.</p><p>The panel also discussed the idea of privacy assurances: simple, understandable promises about what the app does and does not do with user data. Those assurances can become a guiding light for architecture and implementation. If the architecture cannot satisfy the assurance, the design needs to change.</p><p>Avoid vague statements such as &#8220;we care about privacy.&#8221; Explain the actual behavior: what data is used, what stays on device, what is encrypted, what is shared, and what controls the user has.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=2538s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>I am a computer science student studying cybersecurity. Which Apple frameworks or security concepts should I learn first to build a foundation relevant to app security, platform security, and the broader security field?</h2><p>Start with the fundamentals that sit underneath every secure app: memory safety, system isolation, authentication, cryptography, and permission boundaries.</p><p>On Apple platforms, that means learning how sandboxing, entitlements, code signing, Keychain, CryptoKit, Network framework security, data protection classes, and TCC fit together. These are not isolated features; they form the security model your app runs inside.</p><p>For app security, learn how to handle untrusted inputs, how to store secrets, how to design least-privilege data access, and how to use platform APIs instead of inventing your own security mechanisms.</p><p>For privacy, learn the data-flow questions: what data enters the app, where it is stored, whether it leaves the device, who receives it, and whether the user understands and controls that use.</p><p>The panel also encouraged students interested in cybersecurity and privacy to keep an eye on Apple roles, because these teams hire for exactly this kind of work.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=3016s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should a cybersecurity student learn first to build a foundation for Apple app security, platform security, and the broader security field?</h2><p>Start with the platform security fundamentals before trying to memorize every API.</p><p>For Apple platforms, that means understanding sandboxing, entitlements, code signing, Keychain, CryptoKit, Network framework security, data protection classes, passkeys, and TCC. These concepts explain how apps are isolated, how secrets are stored, how permissions are granted, how data is protected at rest, and how the system keeps untrusted code away from sensitive user data.</p><p>For app security, focus on untrusted input, least privilege, credential handling, safe networking, and using platform APIs instead of inventing custom security mechanisms.</p><p>For privacy, learn to map the data flow: what data enters the app, where it is stored, whether it leaves the device, who receives it, and whether the user understands and controls that use.</p><p>The panel also noted that Apple hires for cybersecurity and privacy roles, so students interested in this area should keep an eye on those opportunities.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=3177s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should services handle passkeys if a user deletes one from the server side, and how does the Signal API help with passkey lifecycle management?</h2><p>Passkeys are part of a broad standard, and Apple participates in the standards work around them.</p><p>The panel noted that passkeys only work well if they can sync and interoperate across the ecosystem, so this is not something one company can solve alone. Apple is working with other companies through the standards process to make passkey lifecycle behavior more reliable.</p><p>The practical issue is that servers and clients need a way to understand when a passkey is still valid, has been removed, or should no longer be offered. That kind of lifecycle signaling matters for keeping account state and credential state aligned.</p><p>The panel did not present this as an Apple-only mechanism. It framed the answer as an ecosystem and standards effort, where Apple is involved because passkeys need broad cross-company compatibility.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=3240s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are Apple&#8217;s best practices for protecting sensitive data in memory on macOS, such as passwords, tokens, or cryptographic keys?</h2><p>Start with Hardened Runtime.</p><p>On macOS, Hardened Runtime helps protect your process memory. It prevents common attack paths such as another process injecting unsigned or unverified code into your process, spinning up malicious threads, attaching a debugger, or reading memory in ways that would expose sensitive data.</p><p>If you are asking how to protect in-process memory, the panel&#8217;s first recommendation was to enable Hardened Runtime.</p><p>For secrets that only need to live briefly in memory, the panel suggested thinking about destruction rather than encryption. If a password, token, or key is needed only for a short operation, clear it as soon as you no longer need it. Encrypting data in memory may not be the right answer if the real goal is to minimize how long the secret exists there at all.</p><p>For cryptographic keys, the panel also called out Secure Enclave-backed keys. You can generate a key that is bound to the Secure Enclave on that device, which means that even if an attacker compromises the app, the process, or the device, the key cannot simply be exported and used somewhere else. It depends on the Secure Enclave hardware of that particular device.</p><p>You can also use attestation APIs to prove that a key is held by the device&#8217;s Secure Enclave. That gives the server or relying party more confidence about where the key lives and how it is protected.</p><p>Use Keychain and platform protections for long-lived secrets, avoid keeping sensitive values resident in RAM longer than necessary, and prefer Secure Enclave-backed non-exportable keys when the key should never leave the device.</p><p><a href="https://www.youtube.com/watch?v=K0sFafYm59Q&amp;t=3482s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared practical privacy and security questions throughout the session. Your questions made the discussion useful for developers working with prompt injection risks, Private Cloud Compute, third-party model providers, App Store privacy labels, Xcode agents, CloudKit, SwiftData, passkeys, TCC, Siri AI, telemetry, MDM, trust communication, sensitive permissions, platform security fundamentals, passkey lifecycle, and secrets in memory.</p><p>Question acknowledgments: Tanya/Taya, Claire Casey, Scott G., Ying Shu, Michael row01, Patatita, Evolving This Design, CMD Dev, Brandon 7269, Conil, M3 Elixir, Thumb Drive, D. Vervkin, and the online WWDC audience who submitted and upvoted the remaining Privacy and Security questions.</p><p>Finally, a heartfelt thank-you to David, Yosh, Katie, Dan, Rohit, Emily, and the teams behind the scenes for leading the session and explaining how privacy and security fit into modern app development.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[
WWDC26: Camera and Photo Technologies Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-camera-and-photo-technologies</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-camera-and-photo-technologies</guid><pubDate>Fri, 12 Jun 2026 15:00:48 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/02a87607-cc07-443d-b557-215650457bd2_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Camera and Photos APIs are full of tradeoffs: speed versus quality, preview versus capture, metadata versus UI, and convenience APIs versus low-level control. This lab focused on practical questions around PhotoKit, AVFoundation, Core Image, thumbnails, depth, deferred start, and capture behavior.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>When Reframe or Clean Up is used to modify a photo, does iOS 27 tag it with metadata or content credentials so someone can tell the image was edited by AI?</h2><p>Yes. The file metadata is modified.</p><p>The panel said that IPTC metadata is updated, together with EXIF, and the IPTC metadata reflects which AI modification was used, such as spatial reframe or Clean Up.</p><p>In the Photos app, this information is also visible in the info panel. On iOS, when you swipe up on a photo, the info panel can show which edit was used.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=457s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Keywords were mentioned as a feature coming to Photos. Will there be an API for third-party apps to view or edit keywords?</h2><p>Keywords are available in Photos on iOS, matching a feature that has existed for a long time on macOS.</p><p>In the Photos app, users can see and edit keywords in the info panel. There is also UI for managing keywords and searching by them.</p><p>When exporting, keywords are reflected in IPTC metadata.</p><p>However, there is currently no PhotoKit-level API for fetching, editing, or querying Photos library assets by those keywords.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=531s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When showing thumbnails of images in a lazy grid view that also use matched geometry effect to a full image detail view, what is the optimal way to load thumbnails for performance?</h2><p>Do not decode full-size images when all you need is a thumbnail.</p><p>On the Core Graphics side, there are image-opening options that let Core Graphics use an existing embedded thumbnail if one is available, or decode and scale down the main image as efficiently as possible.</p><p>On the Core Image side, you can request a scale factor when opening images. That lets Core Image scale the image down early in the processing pipeline, so later work operates on the smaller image and runs faster.</p><p>The practical goal is to make thumbnail generation match the UI&#8217;s real size needs. Store or request smaller representations where possible, and avoid doing expensive full-resolution work for grid cells.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=594s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can deferred start cause issues where the user may attempt to capture a photo before the capture photo output has attached to the session?</h2><p>Yes, if you only defer initialization, you can still miss the shot.</p><p>Deferred start pushes initialization work later so the camera can launch quickly. But if the user taps capture before the photo output is fully ready, that can create a race unless you use the right capture behavior.</p><p>The panel pointed to <code>isResponsiveCaptureEnabled</code> on <code>AVCapturePhotoOutput</code>. When enabled together with deferred start, the system adds buffering so the app can launch quickly and still queue the capture even if the output is not fully initialized yet.</p><p>Deferred start was introduced in iOS 26. The common pattern is to prioritize the preview first and defer less critical outputs so the camera feels responsive immediately.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=691s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the best way to get the depth map and the image for a live viewfinder and for the taken image to create a nice 3D effect with both?</h2><p>There are two parts: preview and still capture.</p><p>For a live preview where you want direct access to depth samples, use <code>AVCaptureDepthDataOutput</code> together with the video stream, and use <code>AVCaptureDataOutputSynchronizer</code> so the RGB and depth frames arrive with matching timestamps.</p><p>For still capture, enable depth delivery on <code>AVCapturePhotoOutput</code>. The specific setting mentioned was <code>depthDataDeliveryEnabled</code>on <code>AVCapturePhotoSettings</code>, so the still photo capture includes depth data.</p><p>If you only need a live depth-style preview effect similar to the Camera app&#8217;s cinematic behavior, there is a higher-level shortcut: enable the cinematic video capture API. That can give you the depth effect in the preview without manually handling all depth samples yourself.</p><p>For custom effects, once you have the video/depth or still/depth pair, you can combine them with Core Image filters.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=782s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When <code>photoQualityPrioritization</code> is set to <code>.quality</code>, <code>AVCaptureDevice</code> often overrides manual exposure duration and ISO during capture. Is there a way to know the final exposure settings before the photo is captured?</h2><p>Manual exposure settings are only fully respected for speed-prioritized captures.</p><p>For photo mode, both balanced and quality capture can use multi-image processing and fusion. That may include underexposed and normally exposed frames, and the pipeline chooses capture settings to support that processing.</p><p>So if balanced or quality appears to respect your manual settings, that may only be because the current scene and pipeline happened to choose something close. It is not a guarantee.</p><p>The practical answer is: if you need strict manual exposure control, use speed prioritization. If you use balanced or quality, expect the system to optimize for capture quality and processing needs rather than preserving your manual exposure and ISO settings exactly.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=942s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can you elaborate on <code>PHAsset</code> original resource choice and what it is used for?</h2><p><code>PHAsset</code> original resource choice is related to assets that contain more than one original-like resource, such as RAW plus JPEG or RAW plus HEIF.</p><p>In Photos, users can choose whether edits are based on the RAW image or the compressed image. That choice also affects which resource Photos uses to generate smaller derivatives and thumbnails.</p><p>The new API exposes that choice to developers. You can inspect or change which resource is treated as the original, and therefore which source is used for editing and derivative generation.</p><p>The panel mentioned APIs around content editing input source, and change requests on assets for toggling which resource is considered original.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=1110s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Will iOS 27 support a linear scene-referred preview stream for Bayer RAW capture through <code>AVCaptureVideoDataOutput</code> or <code>AVCaptureVideoPreviewLayer</code>, without tone mapping or computational processing?</h2><p>Today, the way to get scene-referred linear-style data from camera capture is through the log formats, including Log and Log 2.</p><p>The panel explained that if the request is really for RAW data coming out of camera capture and then using the same filters used for still images, that is not currently available.</p><p>For ProRAW capture, the RAW frames include metadata, but that metadata is not compatible with what <code>CIRAWFilter</code> would need to render the image as if it were a still DNG workflow.</p><p>The team said the idea is worth exploring and thanked the developer for filing Feedback Assistant. For now, this is not supported as an out-of-the-box preview stream.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=1200s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For an app that lives and dies by its capture experience, what are the must-have recommendations?</h2><p>Performance and reliability come first.</p><p>A capture app exists to catch moments. If the app launches slowly or misses the shot, the user may not get that moment back. The panel&#8217;s first recommendations were fast launch, responsive capture, and deferred processing.</p><p>But the right capture experience depends on the product. A pro photography app, a social video app, and a playful filtered camera may all need different priorities. The team encouraged developers to understand who the app is for and what differentiates it.</p><p>Use Apple&#8217;s sample code rather than starting from scratch. AVFoundation is large and easy to misuse. A common mistake is driving <code>AVCaptureSession</code> from the main thread, which can block UI during long operations. The sample code shows best practices such as using a dedicated serial queue.</p><p>Also think about the Photos side of the experience. If your app captures photos, users expect those photos to go somewhere. Integrate with PhotoKit permissions thoughtfully: you can request save-only access first, then ask for broader read access only if the app needs it.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=1335s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the optimal recommended way for streaming video and audio simultaneously without sync drift?</h2><p>Use <code>AVCaptureSession</code> for both audio and video when possible.</p><p>Attach a camera input and a microphone input to the same session, then use audio and video outputs from that session. AVFoundation will do the hard work of putting the audio and video samples on a coherent timeline.</p><p>If you use a different audio API, such as AU RemoteIO, you need to synchronize clocks yourself. Each device is backed by a time source, and you may need to convert presentation timestamps between clocks using Core Media timing APIs.</p><p>The usual approach is to preserve the audio timeline and align video timestamps to it, because audio glitches and timing shifts are easier for users to notice than tiny video timing adjustments.</p><p>If you stream over a network, keep the timestamps coherent before sending. On playback, use AVFoundation playback APIs such as <code>AVPlayer</code> or <code>AVSampleBufferDisplayLayer</code> to handle synchronization on the receiving side.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=1676s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Why does ProRAW support 48 MP output from a Quad Bayer sensor, while native Bayer RAW output is limited to binned resolution?</h2><p>ProRAW and Bayer RAW are different kinds of output.</p><p>Bayer RAW contains Bayer sensor data. ProRAW goes through debayering and Apple&#8217;s Photonic Engine-style merging before output. By that point, the data is already linearized RGB, so ProRAW no longer has to care whether the original sensor pattern was Bayer or Quad Bayer.</p><p>Quad Bayer RAW output would not simply be ordinary Bayer RAW at full resolution. It would be Quad Bayer data, and the ecosystem would also need a way to decode it, including support in tools such as <code>CIRAWFilter</code>.</p><p>The panel said this is heavier than it sounds, and encouraged developers who need Quad Bayer RAW output to file feedback.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=1911s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the recommended process to generate and write ISO-conformant gain maps and gain map metadata for HEIF and JPEG on iOS?</h2><p>Apple already covered this in a previous WWDC session focused on HDR and gain maps.</p><p>The panel pointed developers to that session for API details. The high-level answer is that Core Graphics and Core Image both support gain map workflows.</p><p>Core Image gives deep control over the output: the look, the headroom, and how SDR/RGB content is combined with the HDR addition. Core Graphics also supports writing the relevant metadata.</p><p>The ISO gain map specifications have been added to both HEIF and JPEG, and Apple has worked on that standards support. Developers who want to understand the metadata deeply can also look at the underlying specifications.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=2089s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should <code>setPreparedPhotoSettingsArray</code> work together with deferred start?</h2><p>They are complementary, not conflicting.</p><p>Deferred start is about launching quickly: it lets the session get preview running first while deferring initialization for less immediate branches like photo or movie outputs.</p><p><code>setPreparedPhotoSettingsArray</code> is about telling the photo output what the worst-case still capture configuration might be, so the pipeline can pre-allocate resources for that case.</p><p>You can use both. Deferred start moves initialization after preview starts, while prepared settings let the photo output prepare for expensive capture settings. You can also prepare or re-prepare settings later.</p><p>Without deferred start, photo output quality can affect launch time because quality capture may require heavier allocations. With deferred start, preview can start quickly and those allocations can happen later.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=2265s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Will adjusting <code>PHAsset</code>&#8217;s new rating property require a Photo Library change request?</h2><p>Yes.</p><p>The panel said this is handled through <code>PHAssetChangeRequest</code>. The new rating property can be changed per asset, and the rating enum includes unset plus one-through-five values.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=2395s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there a native way to obtain the original file type, such as PNG or JPEG, from a photo selected with <code>PhotosPicker</code>?</h2><p>Check how you configure <code>Transferable</code>.</p><p>The panel suggested making sure you set the <code>UTType</code> explicitly rather than relying on a default image type. If you leave it too generic, you may see output that does not match what you expected.</p><p>There can also be conversion in the picker in some situations. For example, if the user disables sharing location or captions with your app, Photos may convert from some formats such as RAW.</p><p>If everything is coming out as PNG, double-check the <code>UTType</code> used for transfer and review Apple&#8217;s PhotosPicker sample code.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=2430s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there a way to learn about the adjustment plist format that Apple Photos writes, and can those adjustments be imported back into Photos?</h2><p>No public API exists for this today.</p><p>The panel said there is no supported way to decode that adjustment plist or import those Photos app adjustments back into Photos through a public API.</p><p>If this is important for your app, file a Feedback Assistant request.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=2510s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the biggest mistakes developers make when building camera-heavy apps on iPhone?</h2><p>The first big mistake is using <code>AVCaptureSession</code> on the main thread.</p><p><code>AVCaptureSession</code> can block while it reconfigures the capture graph. If you start or reconfigure it on the main thread, your UI can hang. Use a dedicated serial queue for capture session work.</p><p>The second mistake is changing multiple session properties without <code>beginConfiguration</code> and <code>commitConfiguration</code>. If you make disruptive changes one by one, the session may re-evaluate and reconfigure the graph after each change. Wrap related changes in one transaction so the graph is updated once.</p><p>Another common mistake is using <code>AVCaptureVideoDataOutput</code> just to render preview. If you do not need to inspect or modify frames, use <code>AVCaptureVideoPreviewLayer</code>. It is highly optimized. Use video data output only when you need direct access to buffers for processing, overlays, histograms, metadata, or similar work.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=2564s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there any API to access the new Spatial Reframe pipeline used by Photos?</h2><p>No. There is no public developer API for the Photos app&#8217;s Spatial Reframe capability.</p><p>Some parts of ARKit can capture and reconstruct 3D scenes, but that is not the same as a ready-made Photos Spatial Reframe editing pipeline.</p><p>If you are interested in live capture with depth, AVFoundation can use LiDAR depth on supported Pro iPhones, or TrueDepth on the front-facing camera. But that is separate from the Photos app&#8217;s Spatial Reframe feature.</p><p>The panel recommended filing feedback if developers want access to this kind of pipeline.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=2979s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When will camera capture rotation/orientation handling be made easier across iOS, iPadOS, and macOS?</h2><p>The panel acknowledged that orientation handling can be tricky across Apple platforms, because different devices and UI contexts treat orientation differently.</p><p>The recommendation was to use the newer rotation coordination APIs where available, rather than manually building one-off orientation logic for every platform.</p><p>They also encouraged developers to file feedback for cases that are still painful, especially when platform differences make capture output hard to reason about.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=3053s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can third-party apps capture 24 MP photos with depth from both cameras, similar to the system Camera app?</h2><p>The panel&#8217;s answer was cautious: capabilities depend on device, camera, format, and selected capture configuration.</p><p>Depth delivery and high-resolution photo capture are each supported through AVFoundation APIs, but not every combination is available on every device or every camera. Some system Camera app behaviors depend on private pipeline choices or supported formats that third-party apps must query at runtime.</p><p>The practical guidance is to inspect the available <code>AVCaptureDevice</code> formats, supported photo dimensions, and depth delivery support for the exact device and camera you are using. Do not assume the system Camera app&#8217;s full behavior is exposed as a single third-party API combination.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=3265s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers think about multicam capture and streaming from multiple iPhone cameras?</h2><p>Use the supported multicam APIs and design around device limits.</p><p>Multiple simultaneous camera streams can be expensive in terms of processing, memory bandwidth, thermal load, and power. The available combinations depend on hardware and formats.</p><p>For streaming, keep audio/video synchronization in mind, use coherent timestamps, and avoid doing unnecessary per-frame processing on the critical path. If you are only showing preview, prefer preview layers. If you need buffers for encoding or effects, keep processing efficient and expect to manage back pressure.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=3500s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What should developers know about the new camera control APIs and niche capture features?</h2><p>The later part of the lab covered several specialized APIs and edge cases.</p><p>The overall pattern was consistent: query capabilities at runtime, use the most specialized API only when the app really needs it, and file feedback when the system Camera app exposes behavior that third-party APIs cannot yet reproduce.</p><p>For pro camera apps, the team emphasized careful format selection, performance testing, and clear user experience decisions. A feature may be technically possible, but it still needs to fit the app&#8217;s purpose and the user&#8217;s expectations.</p><p><a href="https://www.youtube.com/watch?v=fn4F09dQb3s&amp;t=3530s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared practical Camera and Photos questions throughout the session. Your questions made the discussion useful for developers working on AI-edited image metadata, Photos keywords, thumbnails, fast camera launch, depth maps, still capture, deferred start, responsive capture, photo quality prioritization, PhotoKit resource choice, RAW workflows, gain maps, audio/video synchronization, PhotosPicker, rotation, Spatial Reframe, and camera-heavy app performance.</p><p>Question acknowledgments: Florent INF, Ben, SJK_27, Yelon, Eric, and the online WWDC audience who submitted and upvoted the remaining Camera and Photo Technologies questions.</p><p>Finally, a heartfelt thank-you to Sergey, Matt Deoff, Brad Ford, Ivan Cavo, David Konchon, Jake, and the teams behind the scenes for leading the session and explaining how to build better camera and photo experiences.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: Icon Composer for Beginners Group  - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-icon-composer-for-beginners</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-icon-composer-for-beginners</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Fri, 12 Jun 2026 12:03:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/959aaef0-f34e-44b8-a96b-544cb110a3e9_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Icon Composer is the final authoring step for app icons that use the Liquid Glass rendering system. The main idea from the lab: design the icon clearly first, then use Icon Composer to annotate layers, tune glass behavior, and verify the icon across appearances, sizes, and backgrounds.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>If you&#8217;re designing an icon from scratch today, what would your step-by-step workflow in Icon Composer look like?</h2><p>Start before Icon Composer. First, decide on the visual metaphor for the app: what the icon should communicate, whether it references the app&#8217;s purpose directly, or whether it borrows from a distinctive part of the app&#8217;s interface.</p><p>Then draw the icon in a design tool. The panel recommended thinking carefully about composition, layer organization, and how the artwork will scale. Simple, elegant vector shapes are usually a better foundation than very complex detail, because icons need to work from very small system UI sizes all the way up to large marketing uses.</p><p>After that, export the layers from the design tool as individual files and bring them into Icon Composer. If you export layers at the full canvas size, their relative positions are preserved when imported, which saves time and avoids surprises.</p><p>Icon Composer then becomes the second step: annotate the layers, tune color behavior, choose which layers use Liquid Glass, adjust specular/refraction/shadow behavior, and check the icon in light, dark, clear, mono, and tinted modes.</p><p>Apple provides templates for common design tools, including Figma, Sketch, Illustrator, and Photoshop. The Illustrator template includes a script that helps preserve positioning relative to the canvas.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=722s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When using Icon Composer, what are the most common mistakes developers make that result in icons looking great in Icon Composer but weak on device?</h2><p>The big mistake is not testing the icon in the contexts where it will actually appear.</p><p>An icon can look beautiful on the Icon Composer canvas and still fail at small sizes, in dark mode, in clear mode, in tint mode, or over a busy background. The panel emphasized checking the icon at its smallest and largest common presentation sizes, and using the preview tools rather than judging only the default canvas view.</p><p>Complexity is another common problem. Liquid Glass effects can be subtle and powerful, but they work best when the underlying shape language is clear. Too much fine detail can make the icon weaker once rendered on device.</p><p>Use Icon Composer&#8217;s waterfall-style size preview, appearance previews, background previews, and grid overlays to verify the result. The goal is not only to make the icon attractive, but to make it legible and recognizable across the whole system.</p><p>The old advice still applies: put the icon on a Home Screen, inside a folder, and check it on a real device in daylight. If it does not hold up there, keep simplifying or tuning.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=951s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Many developers already have mature workflows in Figma, Sketch, or 3D tools. What problem was Apple trying to solve with Icon Composer?</h2><p>Icon Composer was created because app icons are not just static images anymore.</p><p>An icon is part brand identity, part product identity, part system UI, and part user-facing object that appears across many Apple devices. It needs to work on iPhone, iPad, Mac, Apple Watch, dark mode, clear mode, tint mode, different backgrounds, different sizes, and future rendering conditions.</p><p>A static bitmap cannot adapt well to all of that. You could ship many separate PNGs, but that creates a large, brittle set of assets that does not evolve with the system.</p><p>Icon Composer gives developers a resolution-independent representation. You provide clear artwork and layer structure, and the system can render it with high quality across device contexts and design modes.</p><p>It also brings the material language of the system into app icons. Liquid Glass can be applied in a way that interacts with individual layers, rather than being a superficial effect placed over the whole icon.</p><p>The broader vision is consistency and adaptability: one source file that can produce a polished icon across many environments while still letting designers tune the result.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=1129s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What concrete recommendations should developers follow to upgrade icons built for the iOS 26 Liquid Glass design system to iOS 27?</h2><p>If you already have an Icon Composer file from last year, open it in the updated Icon Composer first. The new rendering is applied automatically, so you can see how your existing icon looks without changing artwork or annotations.</p><p>From there, review specular highlights, especially if you have overlapping layers. Check what automatic does, then decide whether inside or outside specular works better for the colors and layer structure.</p><p>Review shadows and refraction as well. iOS 27&#8217;s rendering can produce a sharper look, and refraction can be tuned more precisely.</p><p>One major design change the team made in Apple&#8217;s own icons was reducing translucency. This does not happen automatically, so developers should review their own icons and decide whether translucency should be reduced to make the icon sharper and more legible.</p><p>If you still use a legacy bitmap icon, iOS 27 will do its best to segment and adapt it, but you may see choices you do not like. If you want full control, now is the time to invest in an Icon Composer version of the icon.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=1546s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can you explain blend modes in Icon Composer, and when should developers use them?</h2><p>Blend modes define how one layer&#8217;s pixels interact with the pixels beneath them.</p><p>The simplest mode is normal blending: the foreground layer replaces what is underneath. Other blend modes let brightness, hue, color, vibrancy, or darker/lighter relationships from the underlying layers contribute to the final result.</p><p>In Icon Composer, blend modes are useful because glass is not just a flat opaque object. Real glass lets color, brightness, and depth interact. Blend modes help layers feel like transparent or refractive material instead of simple stacked artwork.</p><p>For example, <code>plusL</code> can retain more vibrancy than a standard screen-like blend, which can help an icon feel like colorful glass. <code>plusDarker</code> can help darker relationships preserve color intensity. Multiply, screen, lighten, darken, and the other modes each create different foreground/background relationships.</p><p>There is no single correct blend mode. The panel&#8217;s advice was to try them in context and choose the one that makes the icon&#8217;s layers communicate the right material effect while preserving legibility.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=1845s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>iOS 27 lets users adjust Liquid Glass transparency systemwide. Does Icon Composer let us preview across that slider range, and what should we do if a clear mode icon fails contrast at an extreme?</h2><p>For app icons, clear mode glass does not respond to the systemwide Liquid Glass transparency slider.</p><p>That was a deliberate choice. System glass often knows more about foreground and background content, but app icons can contain almost anything. To keep icons consistent and legible, the glass behavior for clear mode icons is pinned instead of varying with the slider.</p><p>That means developers do not need to design across that slider range for icons. You still need to test against wallpapers, clear mode, dark clear, light clear, and tint modes, but not against every possible system glass transparency value.</p><p>There is one mono mode annotation that supports light clear, dark clear, and tinted modes, so focus on making that mono representation strong.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=2198s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Most app icons start as flat 2D brand marks. How should we think about giving something flat a convincing physical appearance in Liquid Glass?</h2><p>This is exactly the kind of transformation Icon Composer is built for.</p><p>When you bring in a layer, Icon Composer applies a default set of glass properties, and then you can tune them based on the shape, size, color, and structure of the artwork.</p><p>The panel compared this to how brands already adapt logos across media. A logo may appear on paper, on a product, in a motion graphic, or as a physical badge. It is still the same identity, but each medium may require a different treatment.</p><p>For app icons, that may mean exposing layers that were flattened or cut out in the original vector artwork. If a mark has eyes, counters, or cutouts, you may decide those should become separate layers instead of negative space. That can make the icon feel constructed from real materials rather than printed flat.</p><p>The key is to preserve recognizability while adapting the construction for the medium. If the icon still clearly reads as the same brand, adding physicality through layers, glass, refraction, and shadows can make it feel at home in the system.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=2303s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Has anything changed in how updated Icon Composer icons are included in an app in Xcode?</h2><p>No. The integration process is the same as before.</p><p>When you finish designing the icon in Icon Composer, drag the <code>.icon</code> file into your Xcode project as a normal resource, next to your Swift files.</p><p>Xcode should suggest the correct target membership by default, but you can verify it during import.</p><p>Then open the target editor and make sure the app icon name matches the file name you dragged in. Usually that means <code>AppIcon</code>, without the <code>.icon</code> extension.</p><p>This is adjacent to the asset catalog, not inside it. If you already have an app icon in the asset catalog, you likely want to remove it to avoid confusion.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=2517s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Do imported layers inside Icon Composer automatically become glassy in the iOS 27 style?</h2><p>Yes. Imported layers are rendered as glass layers by default.</p><p>However, you can control this. If a layer should remain flat, or if you already prerendered a specific treatment into a raster image, you can turn off Liquid Glass for that layer.</p><p>If your icon has multiple layers, consider organizing them into groups. Glass properties are applied at the group level, so grouping gives you more control over how different pieces of the icon render.</p><p>This is useful for icons that combine vector layers, raster artwork, watermarks, or other elements where not everything should receive the same glass treatment.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=2586s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>In tint mode, my icon background colors look washed out and lack contrast, while clear mode looks better. What settings can I tweak for better vibrancy?</h2><p>First, test in the latest iOS 27 Icon Composer rendering, because the team made tweaks to improve some of these cases.</p><p>Then check the mono mode annotations. The panel recommended maximizing dynamic range: use real darks and bright highlights so the system has enough contrast to work with when transforming the icon into tinted modes.</p><p>Pay attention to your background layer as well. If you supply your own gradient or background, be careful with luminance values, especially in mono mode. In many cases, using the system-provided backgrounds gives you better baseline contrast.</p><p>Foreground elements should usually include white or near-white areas, or at least some strong highlight component, so they remain legible across user-selected tint colors. Some tint colors, such as yellow, are naturally high in luminance, so your icon needs to survive those extremes.</p><p>Finally, inspect the shape detail. Very fine elements or too many small shapes can become weak in tint mode even if the colors are technically correct.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=2668s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For the Apple Developer app icon, what are the main layers? Is it just a border, a background, and the hammer logo?</h2><p>Yes, the Apple Developer icon is relatively simple structurally.</p><p>The panel described it as essentially three major parts: the background, the hammer mark, and a border or rim treatment. The strength comes from the clarity of the metaphor and how those few pieces are tuned, not from a large number of layers.</p><p>This is a useful reminder that Liquid Glass does not require a complicated layer stack. A simple icon can work very well when the core shape is strong and the layers are organized cleanly.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=2960s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should I design icons for color-blind users?</h2><p>Do not rely on color alone.</p><p>The panel recommended thinking in terms of contrast, shape, and clear visual structure. Color can help make an icon feel distinctive, but the icon should still be recognizable when color differences are reduced or transformed by system appearance modes.</p><p>For Icon Composer specifically, mono mode is important. Strong darks, bright highlights, and clear shapes help the icon survive tinted and monochrome transformations. If the icon only works because two colors are different, it may fail for color-blind users or in system modes that reduce or remap color.</p><p>The practical test is to preview the icon in mono, tinted, light, dark, and clear modes, and make sure the key shape still reads.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=3171s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>I am a newbie with no design know-how. How can I make a good-looking app icon in Icon Composer?</h2><p>Start with the app&#8217;s purpose, not with the glass effects.</p><p>The panel&#8217;s advice was to find one clear metaphor that represents the app. A simple mark is easier to make recognizable, easier to test at small sizes, and easier for Icon Composer&#8217;s rendering to adapt across light, dark, clear, and tint modes.</p><p>Use Apple&#8217;s templates and sample files as a learning tool. Open them, inspect the layer structure, see how groups are organized, and try changing one variable at a time. That is a much better way to learn than starting with a very complex icon.</p><p>Do not try to make the first version perfect. Build a simple icon, preview it at the smallest size, check it on a real Home Screen, and ask whether the idea is still recognizable. Then tune the glass, refraction, shadows, and color.</p><p>If design is not your strength, keep the icon intentionally simple. A clear symbol with strong contrast will usually work better than a detailed illustration with lots of effects.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=3180s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are Apple&#8217;s recommendations for balancing one shared Liquid Glass icon with platform-specific tweaks while keeping the brand consistent across iOS, macOS, watchOS, and legacy OS versions?</h2><p>Use Icon Composer as the source of truth where possible.</p><p>The tool is designed to help one icon adapt across platform shapes and system appearances. For example, watchOS has a circular icon shape, while iOS and macOS use different rounded-square presentations. Icon Composer gives you a unified visual system while still letting the renderer adapt the icon to those different destinations.</p><p>For older OS versions, Apple has gone to significant lengths to render a reasonable version of the same icon identity. The goal is that the icon you land on in Icon Composer can still be represented naturally on legacy systems, App Store product pages, and earlier visual contexts, even when those systems do not support the newest Liquid Glass rendering.</p><p>That does not mean the icon will look identical everywhere. Older systems have different design languages and rendering capabilities. But the goal is to preserve the same recognizable brand identity across versions.</p><p>The practical advice is to design one strong, simple icon first, then use Icon Composer&#8217;s platform and back-deployment previews to check where platform-specific tweaks are needed. Preserve the core metaphor and silhouette; tune the rendering details around it.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=3443s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the team&#8217;s favorite new Icon Composer features this year?</h2><p>The panel called out several favorites.</p><p>The updated specular treatment was a big one. It gives glass layers sharper definition, including darker edge details that help describe the shape.</p><p>Refraction also stood out because it gives designers a more direct way to tune the physical feel of glass. You can control the height and strength of the refraction, and even use inverse refraction for different effects.</p><p>The updated shadows were another highlight. Ring shadows and chromatic or neutral shadow options help give icons more realistic material presence.</p><p>Finally, the improved previews matter a lot: checking different appearances, clear mode backgrounds, platform shapes, icon grids, sizes, and back-deployed rendering makes the tool more useful for real shipping work.</p><p><a href="https://www.youtube.com/watch?v=iaXx7XVK8c8&amp;t=3653s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared practical Icon Composer questions throughout the session. Your questions made the discussion useful for developers and designers working on app icon concepts, SVG layer preparation, Liquid Glass tuning, iOS 27 migration, blend modes, Xcode integration, tint mode, clear mode, dark mode, accessibility, cross-platform consistency, and device previews.</p><p>Question acknowledgments: Abashek 3075, Jodor Tree, Jason Chung, Jordan, Kyle, Thomas, SJK27, Andy Zoom01, Macverse, and the online WWDC audience who submitted and upvoted the remaining Icon Composer questions.</p><p>Finally, a heartfelt thank-you to Mike Stern, Patrick Heinen, John Hes, Lance, Liam, and the teams behind the scenes for leading the session and explaining how to move from icon idea to polished system-ready asset.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: SwiftUI Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-swiftui-group-lab-q-and-a</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-swiftui-group-lab-q-and-a</guid><pubDate>Fri, 12 Jun 2026 09:01:47 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/cdd0813f-ac4c-43c4-a3d4-94764c57cbec_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>SwiftUI rewards a different mental model than UIKit or AppKit. This lab focused less on single APIs and more on how SwiftUI wants you to think about architecture, view identity, invalidation, layout, built-in controls, debugging, and performance.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>Is there an architecture like MVC, MVVM, or another pattern that the SwiftUI team expects us to adopt?</h2><p>No. SwiftUI is designed to be architecture-agnostic.</p><p>Use the architecture that fits your app, your team, and your data model. A small app may not need a heavy architecture at all. A large app with many contributors may benefit from stronger conventions and more standardized patterns.</p><p>The important part is not to design the app around a UI framework alone. Your data model also has to support persistence, synchronization, testing, and other app-specific needs. Ideally, your SwiftUI views are a projection of that model into pixels.</p><p><code>@Observable</code> can help here because your model can remain plain Swift code. It can be tested, reused from UIKit or AppKit, and then observed by SwiftUI when you adopt SwiftUI incrementally.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=173s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the difference between an <code>@ViewBuilder</code> closure or computed property and a separate <code>View</code>? Are there performance pros and cons?</h2><p>A computed property or <code>@ViewBuilder</code> helper mostly behaves as if the code still lived inside the original view body. It helps readability, but SwiftUI does not get a new independent view identity from it.</p><p>A separate <code>View</code> is different. It has its own identity and its own <code>body</code>. SwiftUI can track dependencies and invalidation more granularly for that separate view.</p><p>That means extracting a subview can improve performance when only part of a larger view depends on a piece of state. The smaller view can update independently instead of causing the whole parent body to be reevaluated.</p><p>There is no hard lower bound for how small a view can be. Views are lightweight value types. Split when it clarifies the code, isolates dependencies, gives you finer previews, or lets you read environment values in the right scope.</p><p>The same idea applies to modifiers: extracting repeated modifier chains into a custom modifier can provide similar structure and dependency benefits.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=393s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are some common SwiftUI anti-patterns developers fall into?</h2><p>Several patterns came up.</p><p>First, watch for overuse of <code>GeometryReader</code>. If you are using it to drive layout, a custom <code>Layout</code> may be a better fit because it avoids invalidating a larger hierarchy unnecessarily.</p><p>Second, be careful with <code>onChange</code>. It is useful, but if you are using it to trampoline data back and forth, that may be a sign the view is still written in an imperative style. Prefer making the UI declaratively respond to state.</p><p>Third, avoid putting frequently changing values in the environment when many views read them. Environment is useful for passing data through the tree, but if the environment value changes often, every view that declares that dependency may be invalidated. Passing an observable object through the environment can be better when the object identity is stable and only specific properties change.</p><p>Fourth, avoid custom wrapper views around controls when a style protocol is the better tool. If you are wrapping <code>Button</code>only to apply a consistent look, a custom <code>ButtonStyle</code> often keeps you closer to SwiftUI&#8217;s built-in behavior and built-in initializers.</p><p>Finally, be careful with conditional modifiers that add or remove modifiers while the view is on screen. Changing the structure can recreate the view, break animations, reset state, and hurt performance. Prefer inert modifier values, such as changing opacity between <code>1</code> and <code>0</code>, instead of conditionally adding and removing the modifier itself.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=720s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is one SwiftUI concept that takes many developers the longest to understand?</h2><p>A major concept is how SwiftUI updates views.</p><p>SwiftUI does not work like a DOM diff where the framework simply compares rendered output. Internally, SwiftUI maintains a graph of views and dependencies. State changes flow through that graph, and SwiftUI uses those dependencies to decide what needs to be reevaluated.</p><p>This is why dependency scoping matters. If a large view reads a piece of state, the whole view may be reevaluated when that state changes. If a smaller extracted view reads it, SwiftUI can update that smaller unit instead.</p><p>Another common mental shift is that reevaluating a view body is not necessarily the same as redrawing or rerendering pixels. A body can be reevaluated without causing expensive rendering work if the resulting view description does not materially change.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=1155s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Why can <code>ForEach</code> with filtering or <code>if</code> statements become a problem?</h2><p>If you put filtering logic or <code>if</code> statements inside the body of a <code>ForEach</code>, the visual result may look correct, but SwiftUI may need to iterate through the whole <code>ForEach</code> to understand how many views it contains.</p><p>That can hurt performance, especially in large lists or lazy containers.</p><p>A better approach is to filter the data before it reaches the <code>ForEach</code>, so the <code>ForEach</code> receives a collection with a predictable number of elements. If type erasure or structural uncertainty is involved, wrapping content in a container such as <code>HStack</code> or <code>ZStack</code> can sometimes give SwiftUI a constant structural shape to reason about.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=1244s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers think about SwiftUI layout compared with UIKit layout?</h2><p>UIKit and SwiftUI approach layout differently.</p><p>UIKit is often experienced as top-down: the outer container lays out child views and pushes constraints or frames downward.</p><p>SwiftUI often feels more bottom-up. Parents propose sizes, children decide what size they want, and those answers flow back upward. The final layout is the result of that negotiation.</p><p>This difference matters when mixing UIKit/AppKit and SwiftUI. If you build a &#8220;sandwich&#8221; or &#8220;cake&#8221; of interop layers, with frameworks alternating across the hierarchy, you need to be aware that each framework has different layout and invalidation expectations.</p><p>For deeper understanding, the panel pointed to earlier WWDC material on custom layout.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=1425s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What did the new <code>ContentBuilder</code> work change, and why does it matter?</h2><p><code>ContentBuilder</code> improves how SwiftUI handles complex view structures, especially views with many groups, sections, and <code>ForEach</code> blocks.</p><p>The panel used an analogy: older type-checking could feel like exploring every path through a cave. With the newer builder improvements, it becomes more like walking down a hallway.</p><p>The practical result is that SwiftUI code with nested structural containers can type-check more predictably. <code>ContentBuilder</code>also backports because it is effectively a type alias to <code>ViewBuilder</code>, while <code>ViewBuilder</code> itself became smarter.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=1766s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When your teams hit a mystery rerender storm, what is the real debugging workflow? Is it Instruments, <code>_printChanges()</code>, or something else?</h2><p>Use all of the tools.</p><p><code>_printChanges()</code> and <code>_logChanges()</code> are useful for seeing why a view body is being reevaluated. <code>_logChanges()</code> uses OS logging, which can be more convenient in some workflows.</p><p>Another simple visual trick is to temporarily apply a random color to a view. If the color changes unexpectedly, you can quickly see that the body is being reevaluated. This is also useful for comparing a computed <code>@ViewBuilder</code> helper with an extracted subview.</p><p>For deeper investigation, use the SwiftUI instrument in Instruments. It gives a more systematic view of invalidation and view update behavior.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=1879s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the performance tradeoffs of <code>compositingGroup</code> and <code>drawingGroup</code>?</h2><p><code>compositingGroup</code> is less about performance and more about visual correctness. It lets SwiftUI treat a group of views as a single composited result before applying effects.</p><p>For example, if you apply a shadow to a <code>ZStack</code>, you might expect one shadow around the combined visual result, but without compositing SwiftUI may apply the shadow to each individual visual element. <code>compositingGroup</code> lets you apply the effect to the overall result.</p><p><code>drawingGroup</code> is more performance-oriented. It can render many visual layers into a single drawing layer. This can help when you have many on-screen rendered elements, such as a complex custom graphic, and the cost is dominated by layer rendering rather than the number of SwiftUI value-type views.</p><p>That said, it is not a universal optimization. It trades memory and rendering behavior for fewer rendered layers, so profile before using it broadly.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=3481s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When should I use <code>Canvas</code>, and what are its tradeoffs?</h2><p><code>Canvas</code> is useful when you are drawing custom graphics where you do not need each individual piece to be its own SwiftUI view.</p><p>The tradeoff is that the things drawn inside a <code>Canvas</code> are not SwiftUI views. You cannot attach independent gestures to each drawn element the same way you would with separate views. If you need interaction, you may need to do your own hit testing or math.</p><p>Accessibility also needs extra care. A canvas can be visually rich but semantically empty unless you expose an accessible representation. The panel called out <code>accessibilityRepresentation</code> as a useful API: for example, a visual canvas slider could be represented to accessibility as three real sliders.</p><p><a href="https://www.youtube.com/watch?v=7g-Xg5xiH4o&amp;t=3651s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared practical SwiftUI questions throughout the session. Your questions made the discussion useful for developers thinking about architecture, view identity, invalidation, layout, performance, debugging, built-in controls, UIKit/AppKit interop, and accessibility.</p><p>Question acknowledgments: U.J., Azie, Tyler, and the online WWDC audience who submitted and upvoted the remaining SwiftUI and UI Frameworks questions.</p><p>Finally, a heartfelt thank-you to Kurt, Adicha, Jason, Taylor, David, Sema, and the teams behind the scenes for leading the session and explaining how to reason about SwiftUI in real apps.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: Coding Intelligence, Machine Learning & AI - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-coding-intelligence-machine</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-coding-intelligence-machine</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Fri, 12 Jun 2026 06:01:20 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f1ef1c45-96dc-42fb-b55b-a78e4e183df4_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Apple&#8217;s AI stack is no longer one framework or one model choice. This lab covers how Foundation Models, Core AI, Core ML, MLX, Xcode agents, evaluations, Vision, Private Cloud Compute, local models, context management, guardrails, and model deployment fit together.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>Could you explain the roles of Core AI, Core ML, and MLX in simple terms from a beginner&#8217;s perspective? How should one understand them and decide which one to learn or use?</h2><p>Think of Apple&#8217;s machine learning stack as layers, depending on how much control you need.</p><p>If you are building an LLM-based feature, start with the Foundation Models framework. Try the system language model first, then use evaluations to check whether it works for your use case. If you need more capability or a larger context window, use Private Cloud Compute. If you need your own model, you can still plug it into Foundation Models through the language model protocol.</p><p>If your work is not language-model based &#8212; for example diffusion, image segmentation, or another custom neural network &#8212; use Core AI. Core AI is the forward-looking path for neural-network workloads and for bringing custom models into apps.</p><p>Core ML remains available, especially for more traditional ML use cases such as decision trees and similar model types.</p><p>MLX is the lower-level and flexible option, especially useful for training, experimentation, distributed inference, local AI workflows, and cases where you want more direct control over model execution.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=371s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the on-device Foundation Models context window in iOS 27? Is input and output counted against one shared token budget?</h2><p>The on-device system language model context window is 4,096 tokens. It is a shared budget, so input and output both count against the same window.</p><p>For example, if you send roughly 4,000 tokens as input, the model only has about 96 tokens left for output.</p><p>Private Cloud Compute supports a larger 32K context window, also as a shared budget. If you need even larger context windows, you can bring another provider or model through the language model protocol, including Core AI, MLX, or server-backed model packages.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=610s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can Foundation Models run inside a background app refresh task or background processing task, especially while the phone is locked, asleep, or the app has been backgrounded for a while?</h2><p>Yes, Foundation Models can run in the background, including inside background tasks. However, the system may rate-limit the app, especially if the OS is busy.</p><p>If that happens, the system language model can throw a rate-limited error. Your app should catch that error and try again later.</p><p>On macOS, the local Foundation Model should not be rate-limited as long as the app is in the foreground. Private Cloud Compute can also be rate-limited, but for different reasons, such as sending too many requests in a short period.</p><p>The quality of the output is not reduced by background execution. The request either runs or it does not; it may just take longer or require retrying if rate-limited.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=797s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For macOS 27 Apple Intelligence, what does the waitlist mean? Both Siri local and PCC models are working. Are we getting different models on the waitlist? Does this beta include AFM Core advanced 20B?</h2><p>The waitlist applies only to Siri. It does not apply to the Private Cloud Compute language model or to the on-device pieces used by the Foundation Models framework.</p><p>The panel also confirmed that the beta includes AFM Core advanced, used for voice features and related capabilities.</p><p>For deeper Siri-specific details, the recommendation was to bring the question to the Apple Intelligence group lab.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=902s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>The Foundation Models framework now supports bringing your own LLM provider alongside the on-device model and Private Cloud Compute. Can you mix all three within a single agentic flow? What are the data privacy and attribution boundaries once a third-party provider is in the loop?</h2><p>Yes, you can mix them in a single agentic flow. The key API is dynamic profiles, which lets you route different parts of a workflow to different models in a declarative way.</p><p>The panel described two patterns: baton pass and phone a friend.</p><p>In a baton-pass flow, each model receives the full context from earlier steps. That works well when all models have the same privacy expectations, such as staying on-device or within Private Cloud Compute, or when you are comfortable sharing the full context.</p><p>In a phone-a-friend flow, the main model calls another model with only the specific question it needs help with. The other model does not see the full transcript. It returns an answer, and control goes back to the original model. This is better when you want a stronger privacy boundary or when a third-party model should not receive all prior context.</p><p>Dynamic profiles and profile modifiers can also help manage different context windows. For example, you can keep only the last few transcript entries, drop old tool calls after they are used, or shape the transcript differently depending on which model is selected.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=982s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>My app uses on-device speech-to-text and must recognize names and proper nouns that general models miss. Does iOS automatically personalize recognition to each user, learning their words and pronunciations over time, or do I need to build and maintain that list myself?</h2><p>The panel did not have the exact speech framework owner present, so they did not give a definitive API answer.</p><p>At a high level, speech personalization often involves a component that adapts to user-specific words, names, contacts, or pronunciations. Whether the system API already exposes the personalization you need depends on the speech recognition API and language you are using.</p><p>The recommendation was to ask this on the developer forums so the speech framework engineers can answer directly.</p><p>If you need custom behavior beyond the system speech APIs, it may be possible to build your own model or personalization layer, but the panel suggested starting with native speech recognition support first, especially for supported languages.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=1322s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How do you train coding agents to know more about my code style or a specific area? I use a local LLM with Xcode or VS Code, and my complex codebase includes visionOS, Metal, physics simulation, and macros that generate 3D resources, but it does not perform very well.</h2><p>Agents learn best when they can search, inspect, and write down what they discover.</p><p>First, give the agent access to examples from your project. It will often infer style from nearby source code. For stronger guidance, use files such as <code>AGENTS.md</code> or similar project-level instructions. Keep the always-included file short, because it consumes context on every request.</p><p>Reference other markdown files from there. For example, tell the agent where the networking guide, style guide, Metal conventions, or macro documentation live. Then the agent can search those files only when needed.</p><p>You can also ask the agent to document what it learns. If it discovers how your networking layer works or how a crash was fixed, have it write that down so future sessions can reuse the knowledge.</p><p>For Xcode 27, the panel recommended trying ACP support. ACP lets Xcode talk to the agent of your choice, including agents connected to local models through tools like LM Studio or Ollama. This is more capable than a simple chat-completion workflow because an agent can manage state, use tools, inspect files, and work in longer loops.</p><p>The model still matters. Smaller local models can often copy style and follow local conventions, but they may struggle with deep reasoning across a large and complex codebase. Xcode&#8217;s documentation search tools can help ground the model in new Apple APIs during beta periods.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=1496s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>With regards to UI testing, what practical steps can teams take to integrate automated approaches into their testing workflows on Apple platforms?</h2><p>Think of testing in layers.</p><p>Start with small, fast unit tests. Agents are good at helping enumerate cases and generate many focused tests for small pieces of logic.</p><p>Then add a smaller number of integration tests that bring in dependencies and test broader behavior.</p><p>UI tests should be the final layer, not the only layer. They are more expensive and slower, so use them to verify the important connection points in the UI rather than every possible permutation.</p><p>Xcode 27 adds simulator interaction for agents. An agent can tap, swipe, type, inspect screenshots, and read the accessibility tree. That means it can explore an app, find issues, and then help generate repeatable UI tests so you do not need the agent to manually run the same exploration every time.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=2077s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Have there been any updates to Natural Language processing and Apple Vision? Now that Foundation Models support image attachments, what should be the preferred method of image extraction?</h2><p>If there is a specialized API for the task, use that first.</p><p>For well-understood image tasks such as barcode reading, OCR, segmentation, or detecting a known kind of object, Vision or image-understanding APIs are usually the right choice. They are efficient, specialized, and easier to test.</p><p>Foundation Models are better when the task requires semantic understanding, natural-language nuance, or open-ended interpretation. For example, if the user&#8217;s prompt changes the kind of image reasoning needed, an LLM or multimodal model may fit better.</p><p>The panel compared foundation models to a 3D printer: flexible and great for custom jobs. Specialized APIs are more like a production line: faster and better when the task is known and repeatable.</p><p>The same rule applies to translation. If you just need ordinary translation, use the Translation framework. If you need style transfer or unusual natural-language interpretation, then a language model may be appropriate.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=2261s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>On-device LLMs have relatively limited token capacity. What are the best practices for managing prompt size, tool definitions, and context to avoid exceeding limits while still maintaining high-quality responses?</h2><p>Use the token-counting and response-usage APIs in the Foundation Models framework. They let you inspect context size, count tokens, and see input, output, cached, and reasoning token usage.</p><p>When context grows too large, you have several options. You can drop old entries, drop tool calls and tool outputs once they have already been used, or summarize the conversation history.</p><p>Apple open-sourced Foundation Models utilities, including a summarize-history modifier. It can summarize the transcript once it exceeds a configurable size. The default prompt can be overridden, which matters because the right summary depends on your use case.</p><p>There is a tradeoff. Dropping or summarizing context can invalidate the KV cache and increase latency, but keeping too much context can distract the model or hurt accuracy. Use the Evaluations framework to compare strategies on the same dataset and see which one works best for your feature.</p><p>Also avoid asking one session to do too many unrelated tasks. If tasks are independent, split them into separate sessions so each task has a fresh context window.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=2500s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Foundation Models guardrails sometimes refuse emotionally intense but legitimate journal entries, such as grief or venting. Can I prevent refusals on first-person emotional writing, and how do I detect guard refusal versus other errors to fall back gracefully?</h2><p>There are two separate concepts: guardrail errors and model refusals.</p><p>For input moderation, the system language model supports a setting called permissive content transformations. If enabled, the model should not error out just because the input is emotionally intense.</p><p>However, the model may still refuse in natural language to continue or elaborate on certain content. That is a model response, not the same thing as a guardrail error.</p><p>If you are using structured output, the model can throw a refusal error. That is separate from a guardrail error, which comes from a moderation model checking input or output.</p><p>If the behavior does not match your legitimate use case, file feedback. Apple also noted that guardrails have been improved this year to reduce false positives.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=3213s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Apple has historically brought a distinct perspective to areas like design and privacy. What is your guiding philosophy or approach to AI evaluation?</h2><p>Evaluation should not happen only after an AI feature is built. It should start at the beginning.</p><p>The panel described evaluation as the living specification of an AI feature: the set of things the feature should do well, edge cases it should handle, and future headroom it should grow into.</p><p>This leads to an evaluation-driven development lifecycle. You start with a small curated dataset, expand it, run the model or configuration, inspect where it succeeds and fails, and then iterate.</p><p>The Evaluations framework is designed to make that cycle easier. It supports datasets, model judges, comparison across configurations, and workflows where developers can improve the feature instead of guessing.</p><p>The larger philosophy is that AI features are non-deterministic, so validation must be part of design and development from the start.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=3384s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is it possible for models used by different apps on iPhone to be shared across apps? This could help save storage space for users.</h2><p>In general, different apps cannot simply share one downloaded model across the system.</p><p>There are sandboxing, security, scheduling, and resource-management challenges. Even if two apps use what sounds like the same model, they may need different quantization, performance, quality, or memory tradeoffs based on their evaluations.</p><p>Apps from the same developer can share resources through an app group. Core AI model caching can also share resources inside a cache group when you have an app group.</p><p>But a system-wide shared model downloaded once and reused by unrelated apps is not available. If you can use the on-device Foundation Model built into the OS, that avoids increasing your app size and avoids shipping your own model weights.</p><p><a href="https://www.youtube.com/watch?v=bXb18GwYQS8&amp;t=3560s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared practical questions about coding intelligence, Foundation Models, Core AI, Core ML, MLX, evaluations, Vision, local models, Private Cloud Compute, Xcode agents, context management, guardrails, and model deployment.</p><p>Question acknowledgments: Jane Chow, Abi27, RB27, Desa, Indigo J, Claire Case, Pichaya_TR Yysy, Brian CM, John Lee, AO, and the online WWDC audience who submitted and upvoted the remaining questions.</p><p>Finally, a heartfelt thank-you to Shashank, Kevin, Eric, Stephen, Raziel, Angelos, and the teams behind the scenes for leading the session and explaining how Apple&#8217;s AI and machine learning tools fit together.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: Accessibility Technologies Group Lab   - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-accessibility-technologies</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-accessibility-technologies</guid><pubDate>Thu, 11 Jun 2026 15:02:29 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/98758107-3815-43c2-aa2b-dd1b70d57996_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Accessibility is not a final checklist item. It is part of how people actually experience software: reading, navigating, understanding, controlling, testing, and trusting that an app will work for them before they even download it. And for many this feature will bring whole world back again. I recommend you to watch this session.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>What is your best advice for testing usability? Accessibility Inspector to audit elements, Device Hub for testing across different screen sizes &#8212; any other advice?</h2><p>When testing accessibility, screen size and text size should be considered together. Dynamic Type and Large Text often affect layout just as much as a smaller or larger device does.</p><p>A view that works visually at the default font size can fall apart when a user enables an accessibility text size. Sometimes that means labels wrap. Sometimes it means the layout should change entirely so controls remain understandable and tappable.</p><p>So in addition to using Accessibility Inspector and Device Hub, test with larger text sizes early. Make sure your UI is dynamic enough to adapt to both different device sizes and different user text preferences.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=406s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>On most teams, accessibility testing means VoiceOver and then they call it a day. Switch Control, Voice Control, and Full Keyboard Access rarely get a pass. How does your team prioritize across assistive technologies when you cannot test everything? Which one do we most underestimate?</h2><p>The honest answer is that many teams are in exactly that situation. Not everyone has the resources to test every assistive technology deeply. Starting with VoiceOver is still a very good first step.</p><p>VoiceOver testing is approachable: you can turn it on quickly and begin testing without extra hardware. It also gives a lot of value because many assistive technologies share the same underlying accessibility information: labels, traits, elements, grouping, and structure.</p><p>If your VoiceOver experience is strong, Switch Control and Voice Control often benefit from that work too. There are additional APIs for polishing those experiences, but the shared accessibility foundation matters most.</p><p>The panel also emphasized the value of real users. You can get far by testing yourself, but feedback from people who rely on these technologies can reveal problems and expectations you may not notice.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=462s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there any way to override or turn off the system-provided description of an image? I have an app that displays artwork, and VoiceOver reads my provided description immediately followed by the system description. I am using the accessibility label modifier on a SwiftUI image.</h2><p>One possible technical workaround is to remove the image trait, which can stop VoiceOver from treating the element as an image and therefore stop the automatic image description behavior.</p><p>However, the panel cautioned against doing this too quickly. Removing the image trait may also prevent users from accessing newer image-description features, including the ability to ask follow-up questions about the image.</p><p>For artwork, the right answer can be nuanced. The artist-provided description may be the authoritative description, but an AI-generated description can still be useful for a blind user who wants a more literal sense of what is visually present.</p><p>VoiceOver plays a small sound before the generated description, so users can distinguish between your provided alt text and the system-generated description. That distinction may be enough in some cases, and preserving the image trait may give users more options.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=700s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>I&#8217;m a third-year medical student building an EHR for underserved areas. Part of it is a patient portal. What new accessibility technologies and features announced at WWDC would be helpful for patients that I can fold into development now?</h2><p>Accessibility Reader is a strong fit for patient-facing long-form content. It is system-wide and lets users customize a reading experience that works for them, then apply that style to content from different apps.</p><p>Image descriptions and Image Explorer can also help when a portal contains charts, medical imagery, or data-rich visual content. These tools are not only for photographs; they can also help users understand charts and visual information.</p><p>More generally, start with Dynamic Type. A patient portal will likely contain dense and important text, so supporting larger text sizes well is a high-impact accessibility foundation.</p><p>After that, VoiceOver support gives another large win. Add useful labels, make sure navigation order makes sense, and test important patient workflows with VoiceOver enabled.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=826s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>In many places in my app, the user taps a button that triggers a network request. For sighted users I show a progress view in place of the button, then replace the button content. How do I make that accessible to iOS VoiceOver users? I&#8217;d like VoiceOver to announce when the action completes.</h2><p>Use accessibility notifications. For smaller layout changes, a layout-changed notification can tell VoiceOver that something in the UI changed. For larger transitions, a screen-changed notification may be more appropriate.</p><p>You can also pass an accessibility element to move VoiceOver focus, but do that carefully. Users do not want their focus pulled around unpredictably.</p><p>If the main need is simply to tell the user that the action completed, an announcement notification may be the clearest option. You provide a string and VoiceOver speaks it.</p><p>The key is to communicate the state change without making the experience noisy or stealing focus unnecessarily.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=1014s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Are there any updates to the text-to-speech APIs this year?</h2><p>The panel was not aware of new text-to-speech APIs in this release.</p><p>There are improvements on the backend, but no new developer-facing API was called out in the lab. Developers who need specific text-to-speech API changes should file feedback with concrete use cases.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=1101s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Dynamic Type is now available on tvOS. What should tvOS developers think about, and what does the work look like to get ready?</h2><p>Start by learning the current best practices for large text. When accessibility font sizes are enabled, your layout may need to do more than scale text. It may need to reflow.</p><p>The panel specifically recommended the new WWDC session about Large Text on tvOS. Older Large Text sessions are also useful, even if they focus on iOS, because the same principles apply: avoid fixed assumptions, make room for content growth, and test with real accessibility text sizes.</p><p>Accessibility Nutrition Labels also now become relevant for tvOS in this area, because developers can report Large Text support for tvOS apps.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=1134s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>We are very excited about Accessibility Nutrition Labels. Please talk about how valuable they are and any details you would like to expand on.</h2><p>Accessibility Nutrition Labels help users understand whether an app is likely to work for them before they download it. For many users, downloading an app without accessibility information can feel like gambling.</p><p>For developers, the labels are also a way to communicate work that might otherwise be invisible. If your team invested in VoiceOver, Large Text, subtitles, contrast, reduced motion, or other accessibility support, the label lets users see that commitment.</p><p>The panel also noted that the guidelines themselves are valuable. They give teams concrete criteria to evaluate against, which can help teams advocate internally for accessibility work.</p><p>One example shared was a developer at a large organization who used the label effort to help get support inside the company. That kind of visibility can turn accessibility from an afterthought into a visible product quality goal.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=1204s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>I was excited to see that there is a VoiceOver option in the Xcode 27 beta Device Hub, but when I tried to use it, it did not do anything. Is it intended to work on simulators or only on physical devices? Is this the year we can test iOS VoiceOver on a Mac?</h2><p>There is a new XCTest API that lets you test VoiceOver on an iOS device from a Mac. The panel believed it should also work in the simulator, but recommended taking specific failures to the forums and filing feedback.</p><p>The user already included a feedback number, and the panel said they would take note of it.</p><p>There is also an Accessibility forum Q&amp;A, which is a good place to bring detailed issues around Device Hub, XCTest, VoiceOver, and simulator behavior.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=1419s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>We&#8217;re adding VoiceOver support to our macOS app. With this year&#8217;s accessibility updates, is there anything we should revisit? What&#8217;s the recommended way to test accessibility across different assistive technologies on Mac?</h2><p>On macOS, user expectations are different from iOS. Mac users often multitask, use more keyboard shortcuts, and expect faster navigation across sections of an app.</p><p>For VoiceOver on Mac, think beyond labels alone. Consider accelerators: keyboard shortcuts, ways to jump to sidebars, inspectors, and important regions, and workflows that let users move efficiently.</p><p>Many of these are not VoiceOver-specific APIs. They are general Mac app affordances that greatly improve the experience for VoiceOver users and keyboard-heavy users alike.</p><p>For testing, use the accessibility shortcut. On macOS, VoiceOver can be toggled with Command-F5. If you have Touch ID, triple-pressing Touch ID opens the accessibility shortcut. Without Touch ID, Command-Option-F5 opens it.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=1499s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For custom AppKit controls with context menus, hover actions, and custom buttons, what is the right way to expose these so VoiceOver users can discover and perform the same actions as mouse users?</h2><p>Custom actions are often the default answer, but they have tradeoffs on the Mac because users may skip them or not expect them in every context.</p><p>If the actions are important, consider exposing them more explicitly. In SwiftUI, <code>accessibilityRepresentation</code> can let you expose a custom view as a different accessibility structure, such as multiple buttons instead of one complex visual control.</p><p>In AppKit, you can achieve similar results by implementing accessibility children and creating your own accessibility elements, though it is more manual.</p><p>Also consider keyboard shortcuts. If an action is useful for VoiceOver users, it may also be useful for power users and full-keyboard users. Be cautious with hover-only actions, because hidden UI can also be difficult for users with cognitive accessibility needs.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=1678s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How does Apple design accessibility features for people with limited or no use of their hands or arms, including people with limb differences, paralysis, tremors, or temporary injuries?</h2><p>Apple provides a range of options because different users with similar disabilities may prefer very different solutions.</p><p>Examples include Voice Control, Head Tracking, Eye Tracking, Sound Actions, Switch Control, AssistiveTouch, Touch Accommodations, and Reachability. Some users may avoid touching the device entirely. Others may touch it, but need the device to interpret touch differently.</p><p>Touch Accommodations now has a new setup flow in iOS 27. Instead of manually tuning every setting, users can go through a calibration activity, tap targets, and receive a recommended configuration.</p><p>The panel also highlighted on-device eye tracking on iOS. External eye trackers can be very accurate, but they require hardware and setup. Built-in eye tracking can make everyday situations much easier, including something as simple as changing entertainment on an airplane without needing help.</p><p>The larger principle is flexibility: Apple avoids boxing users into one input model and instead provides multiple paths so people can configure the device around their needs.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=1813s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Could you mention some features made with neurodivergent people in mind?</h2><p>Guided Access and Assistive Access are two major features designed with cognitive accessibility in mind.</p><p>Guided Access helps keep someone inside a single app or experience. For example, it can let someone stay in a favorite book, TV show, or FaceTime call without accidentally leaving that context.</p><p>Assistive Access provides a simplified visual and interaction model. It uses larger default text, bigger touch targets, simplified app experiences, and a clearer visual structure. Apple has brought more first-party apps into Assistive Access, including the TV app.</p><p>There are also APIs for developers to create optimized versions of their apps for Assistive Access. Beyond those two features, Screen Time, Speak Screen, Speak Selection, and Accessibility Reader can also be helpful for neurodivergent users.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=2047s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>SwiftUI has a new reorderable modifier. How do I make that accessible to VoiceOver? Dragging and dropping is not an idiom in VoiceOver.</h2><p>The panel did not give a final answer in the lab. They noted that the experience may vary by platform and recommended bringing this to the developer forums.</p><p>Drag-and-drop accessibility can differ between iOS and macOS. iOS drag and drop generally works well with VoiceOver, while macOS may have different behavior and expectations.</p><p>For now, this is a good case for forum discussion and feedback, especially if the new SwiftUI reorderable modifier does not expose the right accessibility interaction in the current beta.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=2198s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>I would love to learn more about the new FaceTime video interpreting feature announced at WWDC. How can third-party apps integrate? How is the interpreting session initiated, and are there entitlements or API restrictions?</h2><p>The feature is not available in the current iOS 27 beta, so the panel did not provide integration details.</p><p>The answer was to stay tuned for more information when the APIs become available.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=2250s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For custom SwiftUI reusable views like labels, icons, and composite wrappers, what is the recommended way to expose stable accessibility identifiers for UI tests and Accessibility Inspector without misusing the accessibility label?</h2><p>Do not overload the accessibility label with test-only information. Labels are for users.</p><p>For reusable views, one practical pattern is to require both an accessibility label and an accessibility identifier when the wrapper is created. That makes the API push callers toward doing the right thing.</p><p>You can also add checks so the label cannot be nil. This helps ensure that future reuse of the component still includes meaningful accessibility information.</p><p>For symbols, icon buttons, and other reusable controls, require a real accessibility label and a stable identifier separately. The label supports assistive technology users, while the identifier supports testing.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=2298s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>At the beginning of an app design project, what process do you recommend for making sure accessibility is built in from the start instead of bolted on later? How does that move from UX research and wireframing into Swift development, testing, and support for different assistive technologies?</h2><p>The fact that you are asking the question is already a strong start. Accessibility is much easier when considered from day one instead of taped onto the app at the end.</p><p>At the design stage, learn how users of different assistive technologies might use a similar app. If you have resources for usability research with disabled users, use them. Real users will find issues and suggest improvements you may not think of.</p><p>For larger teams, showing the real user impact can be powerful. Seeing a VoiceOver user touch a control and hear nothing creates a human connection that abstract requirements often do not.</p><p>Make accessibility part of the same planning conversation as security and privacy. It should be one of the dimensions considered throughout the project.</p><p>During implementation, shared components and wrappers can enforce accessibility labels and identifiers. During late-stage polish, reserve time to refine the VoiceOver and Dynamic Type experiences after the UI has stabilized.</p><p>Finally, do not only measure impact by the number of users. Also consider criticality. A feature may affect fewer users but be absolutely essential for those users to use the app at all.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=2388s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>There are a lot of resources on accessibility for iOS, with fewer resources tailored to other targets. Are there platform-specific pitfalls to look out for when developing a universal app for macOS, iPadOS, watchOS, tvOS, and other platforms?</h2><p>A universal app still needs platform-specific testing. If an app works well on iOS, it may still need adjustments for iPad, Mac, TV, or Watch.</p><p>Accessibility is the same way. Test VoiceOver on iOS, but also test VoiceOver on macOS if you ship a Mac app. User expectations are different. Mac users may expect keyboard shortcuts, inspectors, sidebars, and fast navigation. iOS users may rely more on hit testing and touch exploration.</p><p>So the pitfall is assuming one accessibility pass covers every platform. Shared SwiftUI code helps, but each platform has different interaction models and different accessibility expectations.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=2799s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>With these new improved AI voices, will any of them be available for VoiceOver?</h2><p>VoiceOver voices are not just general-purpose system voices. They are specifically tuned for screen reader use, where people often listen at very high speech rates.</p><p>That means a voice that sounds natural in ordinary spoken content may not necessarily be the best fit for VoiceOver. The panel did not announce a simple &#8220;all new AI voices are available for VoiceOver&#8221; answer. Instead, they emphasized that VoiceOver speech has its own requirements and tuning.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=3199s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Besides manual testing, how do you prevent accessibility regressions? What about approaches like accessibility snapshot testing or automated UI testing with accessibility assertions?</h2><p>Automated UI testing is one of the strongest tools here because <code>XCTest</code> and <code>XCUITest</code> rely on the accessibility hierarchy across Apple platforms. If your accessibility hierarchy breaks badly, your UI tests may fail as a result.</p><p>You can also add explicit assertions for accessibility labels and other accessibility properties. For example, tests can check that important controls have labels and that the accessibility hierarchy exposes the elements your app depends on.</p><p>There is also a new VoiceOver testing API. It can start VoiceOver, navigate element by element, and validate what VoiceOver speaks or whether it reaches expected controls. That can be useful for smoke tests that verify VoiceOver can navigate key screen elements and does not encounter silent controls.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=3242s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>I&#8217;m a blind iOS developer. Are there any accessibility improvements in Xcode and developer tools in general this year?</h2><p>Terminal accessibility has improved. VoiceOver can move to visible beginning, access marks better, and read tab-completion suggestions more reliably.</p><p>Xcode also has multiple VoiceOver bug fixes in the current seed. The panel noted that SwiftUI itself is a big accessibility win for blind developers because UI can be defined and edited in code, instead of relying on a visual interface builder workflow.</p><p>Xcode also has useful VoiceOver rotors for navigating code, including jumping between methods, errors, warnings, and variable names. The panel said there is still work to do and encouraged developers to keep filing feedback.</p><p>They also called out AI as a potential game changer for developer tools, especially because it can help summarize, inspect, and explain code in ways that may reduce the need to visually scan large files.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=3336s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>I&#8217;m curious if you have recommendations for making RealityKit or 3D content accessible.</h2><p>RealityKit and spatial content need accessibility design too. The panel referenced prior WWDC material covering how to make RealityKit content accessible, including APIs for exposing spatial content to assistive technologies.</p><p>The main idea is that spatial or 3D content should not become invisible to users who rely on VoiceOver or other assistive technologies. You need to expose meaningful accessibility information for objects, interactions, and scene structure, not only render them visually.</p><p>The recommendation was to watch the dedicated session on making spatial content accessible, because it covers these APIs and design patterns in more detail.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=3565s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Assistive technology is for everyone. I use VoiceOver and Dictation all the time even without a disability.</h2><p>The panel highlighted this as an important point. Accessibility features often help far more people than the original audience they were designed for.</p><p>VoiceOver, Dictation, Large Text, captions, spoken content, and many other tools can be useful situationally, temporarily, or simply as a personal preference. This is one reason accessibility should be treated as core product quality, not a niche feature set.</p><p><a href="https://www.youtube.com/watch?v=1juOcrja4bo&amp;t=3648s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared practical, thoughtful accessibility questions throughout the session. Your questions made the discussion useful for developers working on VoiceOver, Dynamic Type, Switch Control, Voice Control, Accessibility Nutrition Labels, Device Hub, macOS accessibility, AppKit, SwiftUI, cognitive accessibility, mobility access, testing, and universal app design.</p><p>The uploaded transcript does not include stable attendee nicknames for most questions, so the acknowledgments avoid inventing names. Question acknowledgments: the online WWDC audience who submitted and upvoted the Accessibility Technologies questions.</p><p>Finally, a heartfelt thank-you to Cole, Julia Sonen, Drew, Greg, Sil, and the accessibility team behind the scenes for leading the session, sharing practical guidance, and explaining how to build accessibility into app experiences from the start.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: visionOS Group Lab  - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-visionos-group-lab-q-and-a</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-visionos-group-lab-q-and-a</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Thu, 11 Jun 2026 12:03:36 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/feb6cd3a-bdda-46b6-b08d-edf323e9fe6c_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>visionOS is still young enough that many of the best questions are not only about APIs. They are about workflows, debugging, 3D asset pipelines, spatial accessories, WebXR, visual intelligence, testing, and how to design experiences that feel native to Apple Vision Pro instead of simply ported from another platform.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>As an independent developer, what is the best way to gain access to the front-facing cameras for learning or trying something for an app? Do you need to be part of an enterprise development group, or is it impossible for an individual developer to gain access?</h2><p>Access to the main cameras on Apple Vision Pro exists, but it is handled through an application process and is primarily intended for professional and enterprise-oriented use cases.</p><p>It is not limited only to developers in the Apple Developer Enterprise Program. Developers with a standard Apple Developer Program account can apply as well, especially when the account is tied to a business and the app has a concrete use case that requires camera access.</p><p>If you have a real use case and cannot access the capability today, post in the developer forums and file feedback. Apple specifically asked developers to share use cases that would benefit from front-facing camera access, because that helps the team understand where broader access or different APIs may be needed.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=536s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Hitting a breakpoint in an immersive space means standing inside a frozen universe of your own making, squinting at Xcode through passthrough. How do you debug on device? Am I missing a trick?</h2><p>Use Mac Virtual Display inside the immersive environment. There is a developer setting that allows Mac Virtual Display to appear while you are in an immersive experience. That lets you keep Xcode visible while staying inside the app you are debugging.</p><p>This helps both productivity and safety. When a breakpoint hits, you do not need to leave the headset, remove the device, or try to inspect Xcode awkwardly through passthrough. You can keep the immersive context, inspect the breakpoint, and continue iterating.</p><p>The panel noted that this is also a common internal workflow: develop in Xcode through Mac Virtual Display while running the immersive content alongside it.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=666s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Are any of the agent skills Apple is providing this week especially relevant for visionOS development?</h2><p>The most directly relevant skill is the one that helps resize an existing iOS app for visionOS. A 2D iOS interface usually assumes a particular form factor, density, and layout. On visionOS, those assumptions often need to change.</p><p>The skill is meant to help translate iOS UI into a form that better fits visionOS, while preserving platform best practices and principles. It is especially useful when bringing an existing iOS app to visionOS rather than starting from a fully spatial design.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=756s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is your usual workflow for exporting 3D models into USD? Some tools apply different transforms or remove certain materials on complex models. The usual models are FBX or GLB files.</h2><p>The recommended approach is to start with USD as early as possible in the pipeline. If you can export directly from the original 3D content creation tool into USD, that is usually better than transiting through another format first. Intermediate formats can leave their own &#8220;fingerprints&#8221; on transforms, materials, or scene structure.</p><p>There is still variability between 3D tools and how they export data, because the industry is still adopting USD at different levels of maturity. But starting from the original authoring tool and exporting USD directly gives you the best chance of preserving intent.</p><p>If you are iterating on models, consider loose USD formats such as USDA or USDC instead of repackaging an entire scene every time. That can make iteration faster because individual files can be modified without rebuilding the whole package.</p><p>The panel also noted that the USD core specification is now available, which makes it easier for modern AI tools to understand USD structure and potentially help inspect or repair model issues.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=813s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can spatial accessories be tracked outside the range of direct view? I&#8217;m imagining foot trackers, but obviously the user will not always be looking down at their feet.</h2><p>Spatial accessories use a combination of Bluetooth, an IMU, and infrared emitters that Apple Vision Pro can see with its infrared cameras. The IMU can continue providing motion information even when the accessory is briefly occluded or not perfectly visible.</p><p>That said, tracking fidelity depends on the accessory, distance, occlusion, size, and whether the Vision Pro cameras can see the infrared constellation. If an accessory is behind the body or far down near the feet, tracking quality may vary depending on the use case and required precision.</p><p>visionOS 27 opens the spatial accessory specification so developers and hardware makers can build new accessories. Companies such as DF Robot and MikroE were mentioned as providing components or boards that can be used to prototype accessories.</p><p>There is also a new debugging mode that shows the infrared feed Vision Pro sees, which helps you verify whether your accessory is visible in the positions you care about.</p><p>For foot-tracking use cases, Apple specifically asked for feedback explaining why lower-body tracking is needed and what the experience is trying to achieve.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=962s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>When using Gaussian splatting, we notice that the splats are culled if you move your face close or inside the splat. We are trying to reconstruct an immersive scene through sensor data for telepresence. The culling is not ideal. Is there a way to disable this?</h2><p>There does not appear to be a way to disable that vignette or culling behavior today.</p><p>The behavior is not limited only to Gaussian splats. Similar treatment can apply to 3D content that gets too close to the user&#8217;s face, because the system tries to preserve an unobstructed field of view and avoid uncomfortable or unsafe experiences.</p><p>Apple asked developers with this kind of use case to file feedback. The panel emphasized that Gaussian splats are a new and evolving area, and concrete use cases are especially important. A telepresence scene is different from a small scanned object, so feedback should include the creative intent, sample project if possible, and screenshots or screen recordings showing the issue and distance where it happens.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=1228s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is Gaussian splat rendering supported on platforms other than visionOS? The documentation shows support for iOS, but Xcode does not show the symbols available.</h2><p>Gaussian splatting should generally be supported across both iOS and visionOS. If the documentation and Xcode availability do not match, that is a beta issue worth filing as feedback.</p><p>The panel encouraged developers to file feedback when documentation says an API is available but Xcode symbols are missing or the feature does not work as expected. During beta, this kind of mismatch is exactly the sort of issue Apple can still investigate and correct.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=1420s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Why aren&#8217;t there user profiles like on Mac? I want to put on the headset and choose who I am: owner, child one, child two, grandma.</h2><p>Apple Vision Pro is treated more like a deeply personal device, closer in spirit to an iPhone or iPad than a Mac with multiple user profiles. The device is calibrated to a primary user, including eyes and hands, and the experience is designed around that personal model.</p><p>That said, Apple has been reducing the friction of sharing. Guest User workflows have improved, and enrollment can be saved to an iPhone. After someone completes enrollment once, they can store it on their iOS device, and the next time they use another Vision Pro in Guest User mode, the phone can present an App Clip code to restore that setup quickly.</p><p>There is also Guest User with nearby device, where an iPhone or iPad paired to the same iCloud account can help approve access and mirror what the guest sees. So while full Mac-style profiles are not the model today, sharing workflows have become much faster.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=1473s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there any API to detect the lips and face of the owner and mimic that on 3D, like Persona but differently?</h2><p>The ARKit face tracking API is iOS-only. visionOS does not provide raw face or lip-tracking data to third-party apps in the same way.</p><p>Third-party apps can access a camera-style video feed containing the user&#8217;s Persona for use cases like video conferencing, but not raw face geometry or data that would let you build custom lens-style effects or drive a different 3D face directly.</p><p>The panel said this is an interesting use case and recommended filing feedback with details about what you want to build.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=1620s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For visual intelligence on Apple Vision Pro, when Siri answers questions about content the user is looking at, either app windows or real-world objects, does a third-party app need access to the main camera, or is visual intelligence handled entirely at the system level?</h2><p>Visual intelligence is handled at the system level. Third-party apps do not need camera access for this capability, and the information is not shared with third-party apps.</p><p>The panel emphasized that this is done in a privacy-preserving way. The system can answer questions about what the user is looking at, but that does not mean an app receives the raw camera feed or scene data.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=1692s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For apps that support game controllers but are not games, how does Apple envision controllers fitting into the long-term interaction model of visionOS alongside eyes, hands, and voice? Are there new controller capabilities in visionOS 27 that developers should design for today?</h2><p>The input model depends on the experience. Eyes and hands remain fundamental because they map naturally to how people interact with the physical world: you look at something, then reach or act on it. Voice also fits many workflows.</p><p>Controllers and spatial accessories are useful when they add something beyond natural input: precision, haptics, physical affordances, repeatable controls, or specialized interaction. Examples include a stylus-like accessory for refined input, PlayStation VR2 Sense controllers for games, traditional game controllers, or custom spatial accessories built with the newly opened specification.</p><p>visionOS 27 expands this direction by opening spatial accessory support so developers can build custom tracked hardware. These accessories can integrate at the system and SDK level, while still fitting into the broader visionOS interaction model.</p><p>The guidance is not to use a controller just because it exists. Use it when it meaningfully improves the experience.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=1748s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Are there any updates to WebXR in Safari with visionOS 27? In particular, immersive AR mode. We released a WebXR app and would love to run it with immersive AR mode enabled, but we are currently limited to immersive VR only.</h2><p>Safari on visionOS supports WebXR, but the panel described it as immersive-only rendering mode today.</p><p>For AR-style experiences, Apple encouraged developers to also look at the native platform APIs, because visionOS has a rich set of APIs for spatial and augmented reality experiences. Those APIs may allow a deeper integration than the current WebXR path.</p><p>The panel also mentioned web-side improvements such as the model tag, which lets web pages surface 3D content and personal environments without using WebXR in the same way.</p><p>If a WebXR app needs a specific AR capability, the recommendation is to file feedback and include the app link, desired behavior, and concrete use case.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=2009s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For visual intelligence on visionOS, is it purely camera-based, or does it leverage the depth sensors under the hood?</h2><p>The panel did not disclose the exact implementation details. The high-level answer is that Apple aims to provide the best possible result on each platform using the sensors available on that device.</p><p>Different devices have different cameras and sensors, so there is not necessarily one identical implementation everywhere. The system can blend data from available sources depending on the device and the context of the query.</p><p>The same general principle applies across visionOS features such as mapping, hand tracking, and spatial understanding: the system uses the sensor data that makes sense for the experience while preserving the platform&#8217;s privacy and interaction model.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=2170s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>The device sleeps the instant it leaves your head, taking the debug session with it. What is the sanctioned way to keep it awake on a desk during development?</h2><p>There is no &#8220;keep awake on desk&#8221; mode equivalent to caffeinating another device. The reason is security: taking Vision Pro off is effectively the lock gesture. The expectation is that the next person who puts it on must authenticate with Optic ID or passcode.</p><p>The practical workflow is to use Mac Virtual Display while wearing the device. That keeps Xcode, SwiftUI previews, and Reality Composer Pro workflows available in headset while you build and iterate.</p><p>If you do need to remove the headset, having Optic ID configured makes returning much faster. The panel described Mac Virtual Display plus Optic ID as the common development workflow.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=2265s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Can you give us an update on automated testing for visionOS, ARKit, and RealityKit?</h2><p>For RealityKit, look at <code>RealityRenderer</code>. It can drive RealityKit rendering programmatically and can be useful for automated tests or other non-interactive rendering workflows.</p><p>The panel also recommended new testing sessions, including &#8220;Migrate to Swift Testing&#8221; and &#8220;Get the most out of Device Hub.&#8221; Device Hub can support more testing workflows than many developers may expect.</p><p>RealityKit is written in Swift, so existing Swift testing and Xcode testing infrastructure should also apply where appropriate.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=2359s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What are the biggest mistakes new visionOS developers make?</h2><p>One major mistake is assuming that an app that works in the simulator will feel right on device. On Vision Pro, information density, window size, tap target size, and interaction style feel very different because users interact with eyes and hands in a spatial environment.</p><p>Another mistake is stopping at a direct 2D port. A good visionOS app should consider what is uniquely possible on Vision Pro. For an e-commerce app, that might mean letting users pull a 3D product model out of the window and place it on a desk or floor. For other apps, it might mean using room understanding, lighting, spatial placement, or immersive presentation.</p><p>The panel compared this to the early iPhone transition. Early apps often copied old interaction models, but the most interesting apps eventually embraced touch as a new medium. visionOS is at a similar stage: developers should explore what spatial computing makes newly possible rather than only reproducing existing UI patterns.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=2450s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Regarding agentic coding in visionOS, I tried agentic coding in Xcode to generate a Vision Pro visionOS project &#8212; just a Hello World entity in a <code>RealityView</code>, following a local LLM WWDC26 session &#8212; but it generated the app with wrong syntax. Is there any way to fix this or teach the AI to know more about visionOS code?</h2><p>Generated code can be wrong, especially when APIs are new and models were trained on older versions of frameworks. The first recommendation is to be deliberate with prompts and always verify the generated output. Treat it as &#8220;trust, but verify.&#8221;</p><p>For local models, Apple&#8217;s sample projects can help provide better context. Examples mentioned include Hello World, Petite Asteroids, Canyon Crosser, and the newer Model Manipulator sample. Feeding or referencing strong sample code can help the model produce more accurate visionOS and RealityKit patterns.</p><p>The panel also noted that some local LLM experiments can work surprisingly well, but results will vary. visionOS APIs move quickly, so there may be a transition period where models lag behind the latest SDK syntax. Smaller prompts, real sample projects, and compile-checking the output are the practical workflow.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=2840s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>For Object Tracking, how fast it can get now? What will be possible frame rate and latency?</h2><p>visionOS 27 improves object tracking in a few important ways. First, the Object Tracking tool in Create ML has been improved so it can support more kinds of shapes. The earlier version worked best when objects had enough visual features and clear geometry; the new version can handle a wider range of objects.</p><p>Second, RealityKit and ARKit now align object-tracking updates with frame display time. That matters when you are rendering content against a tracked object, because you no longer have to guess whether the tracking update corresponds to the previous frame or the next frame. The tracked pose is aligned with the actual frame being presented.</p><p>The practical advice is to use the new tool, test with the real object, and file feedback with sample assets or recordings when tracking quality is not good enough. For larger or awkward physical objects, it may still be better to track a smaller attached feature or use a spatial accessory.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=3045s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Vision Pro has awesome sensors and impressive frameworks like Persona Kit and CoreIK running under the hood. Will Apple expose more of these to developers, particularly for accessibility-focused telepresence apps for disabled users working in hybrid environments?</h2><p>Apple did not announce new access to those lower-level internal capabilities in this lab. The answer was to file feedback with the exact accessibility and telepresence use case.</p><p>The panel emphasized that Apple cares deeply about accessibility, and that concrete use cases matter. A general request for access to internal frameworks is less useful than a clear explanation of the user need, what you are trying to build, what data or capability is missing, and why current public APIs cannot solve it.</p><p>The discussion also noted that accessibility features often help many more people than the original target group. So if the request is tied to disabled users, hybrid work, or telepresence, it is especially worth documenting carefully in Feedback Assistant.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=3208s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Is there any way to use Mac Virtual Display with a shared Mac or an enterprise Mac setup, especially where the Apple ID on the Mac and Vision Pro may not match?</h2><p>The recommended path is to file feedback for the exact enterprise or shared-device scenario. Mac Virtual Display is designed around a personal workflow, and some enterprise environments introduce constraints around Apple IDs, device ownership, and managed hardware.</p><p>The panel did not give a workaround or announce a new capability here. The key point was that Apple needs concrete details: whether this is a shared lab Mac, a managed enterprise Mac, a device used by multiple employees, or a training/development setup. Those details help the team understand what kind of support would actually solve the problem.</p><p>For day-to-day development today, the strongest recommended workflow remains Mac Virtual Display with the developer&#8217;s own Mac and Vision Pro, especially when debugging immersive content.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=3325s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Are Gaussian splats supported in USDZ files, and can they be distributed through the same workflows as other USD content?</h2><p>Gaussian splats are tied to USD workflows, but the exact packaging and support details depend on the current beta tools and APIs. The panel&#8217;s broader recommendation was to file feedback when documentation, Xcode symbols, or asset behavior do not line up with what you expect.</p><p>Because Gaussian splatting is still a new area for RealityKit and visionOS, concrete examples matter. If a USDZ packaging workflow does not work, include the asset, the expected result, the observed result, and any sample project needed to reproduce the issue.</p><p>This is especially important during beta, when format support, tooling behavior, and documentation can still be clarified or corrected.</p><p><a href="https://www.youtube.com/watch?v=NWwrdciI74M&amp;t=3565s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>&#127942; Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared thoughtful visionOS questions throughout the session. Your questions made the discussion useful for developers working on camera access, debugging workflows, USD pipelines, spatial accessories, Gaussian splats, visual intelligence, WebXR, testing, native visionOS design, agentic coding, object tracking, accessibility, travel scenarios, and thermal behavior.</p><p>Question acknowledgments: Wes Matlock, Thomas Bastible, Jodor Tree, Sismeia, Eric, Ethan, Oliver Cologne, Dilliam, Raymond Yay, and the online WWDC audience who submitted and upvoted the remaining questions.</p><p>Finally, a heartfelt thank-you to Adesh Pavani, Katie, Norman, John, Matt, and Travis for leading the session, sharing practical guidance, and explaining how to think about visionOS as a spatial platform rather than just another screen.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[WWDC26: Power and Performance Group Lab - Q&A]]></title><description><![CDATA[Direct answers from Apple Engineers during WWDC26]]></description><link>https://antongubarenko.substack.com/p/wwdc26-power-and-performance-group</link><guid isPermaLink="false">https://antongubarenko.substack.com/p/wwdc26-power-and-performance-group</guid><dc:creator><![CDATA[Anton Gubarenko]]></dc:creator><pubDate>Thu, 11 Jun 2026 09:02:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7dc00a29-3b74-4e42-9615-2f69cdfec7d2_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Power and performance work is easy to postpone until the app feels slow, drains battery, or starts showing bad field metrics. But the best answers from this lab all point in the same direction: measure first, understand the real bottleneck, and optimize the parts that users actually experience.</p><p>As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.</p><blockquote><p>I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.</p></blockquote><p>Enjoy! And subscribe so you don&#8217;t miss the next Lab.</p><div><hr></div><h2>As a beginner in iOS development, what are the main factors that affect app power usage and performance in SwiftUI, and how can I design simple apps that avoid battery drain and lag?</h2><p>For SwiftUI, start by separating views from their inputs. Make sure views are only watching the state they actually depend on. If a variable changes but a view does not visually depend on it, that change should not cause unnecessary redraws.</p><p><code>@Observable</code> helps here because SwiftUI tracks only the fields a view reads. That gives you a cleaner dependency model and helps avoid updates for data the view does not care about.</p><p>Use Instruments to confirm what is really happening. The SwiftUI instrument can show view updates and dependency relationships, including cause-and-effect graphs. If the issue is power-related, use Power Profiler as well. SwiftUI performance work often improves power too, because reducing unnecessary computation also reduces energy use.</p><p>But do not assume SwiftUI is the problem. If you are new to performance work, start with the overall picture. Your battery drain might come from an algorithm, file I/O, networking, location, or background work. Measure first, then decide where to optimize.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=366s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What&#8217;s the biggest power mistake you see in many apps that developers don&#8217;t realize they&#8217;re making?</h2><p>One of the biggest mistakes is not having enough telemetry or instrumentation. Without measurement, developers often optimize the wrong thing. A single customer report can point to one issue, while field analytics may reveal a broader and more important power problem.</p><p>Another common issue is not accounting for different app states and data sizes. A database write might look fine during local testing but become expensive for users with much larger datasets. That can show up in Xcode Organizer energy logs even if you never reproduce it at your desk.</p><p>You also need to remember that everything uses power: file system access, network requests, location updates, CPU work, GPU work, and display usage. If you can do less work, batch work better, or make network requests half as often, that can be a direct power win.</p><p>Use real-world profiling where possible. Power Profiler supports untethered workflows, where you record traces on-device for longer periods and analyze them later. That helps capture behavior that may not appear in a controlled desk setup.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=728s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>What is the best documentation for Instruments? Are there any written guides?</h2><p>The recommended starting point is the Instruments tutorials. They were written by an Instruments engineer and are designed to feel like someone is walking you through the app step by step.</p><p>The tutorials include an associated project with built-in performance issues, so you can learn the full loop: profile the app, identify hangs or slow paths, understand how they appear visually, fix them, and then verify the improvement.</p><p>For beginners, Time Profiler with the flame graph view is also a good first tool. Flame graphs make it easier to see where time is going because the expensive call stacks are visually obvious. Top Functions is another useful view because it flattens the call tree and shows expensive helper, compiler, and runtime functions more directly.</p><p>If documentation is missing for a specific workflow or instrument, the panel encouraged developers to file feedback.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=916s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Our app shows UIKit and SwiftUI screens without much background work, but it is still using high battery according to Xcode. What are the best practices to know what is going on and why this might be happening?</h2><p>First, distinguish foreground energy from background energy. UIKit and SwiftUI work should usually show up as foreground energy. If you are seeing background energy drain, look for background tasks, location work, networking, or other work scheduled while the app is not in the foreground.</p><p>Power Profiler is a good starting point, especially in untethered mode. Record a trace on the device while using the app in realistic conditions, then bring the trace back to the Mac and inspect it in Instruments.</p><p>Power Profiler can break down energy use by subsystem, such as CPU, GPU, display, networking, and other sources. That helps narrow the issue. For example, high display energy may come from brightness or frequent visual changes, while high network energy may point to background requests.</p><p>Do not rely only on what you can reproduce while tethered to Xcode. Some power problems only appear when the app is used in real-world conditions.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=1060s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>A theme object like colors and tokens is injected through <code>EnvironmentObject</code>and read in every atomic component, dozens of nesting levels, hundreds of components on screen. At what scale does this become a bottleneck, and is there a recommended alternative?</h2><p>There is no single numeric threshold. The cost depends on what the views are doing, how often the environment value changes, and how much downstream work those changes cause.</p><p>Putting values in the environment can be a useful abstraction for passing data down a view tree. The important question is whether changing that environment value causes a large amount of unnecessary invalidation.</p><p>Use the SwiftUI instrument to see the downstream effect of those changes. It can help you understand whether the environment object is actually causing expensive updates or whether it is fine in your specific case.</p><p>If the object changes frequently and many views read it, you may need to split the data, move rapidly changing values closer to the leaf views that need them, or reduce the amount of state that is globally injected.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=1208s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How would you load large data sets like 50,000 or 500,000 records in SwiftUI tables, and how would you analyze performance and regressions using MetricKit?</h2><p>Start by asking how much data the user experience actually needs to load at once. If the UI is not displaying all 500,000 records, loading everything immediately is probably unnecessary work.</p><p>Load only what you need. Use batching, pagination, lazy containers, and model-side filtering so SwiftUI receives the data it actually needs to display. SwiftUI has lazy stacks and lists that can help load views as they come on screen.</p><p>For MetricKit, use state reporting to understand what the app was doing when a metric changed. Rather than logging a rapidly changing number like the exact item count on every update, group states into meaningful categories such as small, medium, and large batch sizes. That gives you useful slices of performance data without creating excessive logging overhead.</p><p>This lets you compare how different loading strategies behave in the field, and it helps you decide where to invest optimization effort.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=1288s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How does iOS 27 prioritize background tasks when the system is under heavy Apple Intelligence workloads?</h2><p>It depends on which system resources are being used. Many Apple Intelligence workloads run on the Neural Engine or in Private Cloud Compute. If your app is using CPU while the intelligence workload is using a different resource, they may be able to run at the same time without much conflict.</p><p>Still, background tasks should be designed in small chunks. If the system needs to pause or delay work, your task should be able to resume without starting over from the beginning. That makes progress more reliable even when the system is busy.</p><p>Instruments also adds more visibility here. System Trace can show thread priorities and help you understand whether you are assigning QoS incorrectly, or whether another task preempted your thread.</p><p>The general principle is that the system tries to schedule work automatically to preserve the best user experience. Your job is to make background work resumable, appropriately prioritized, and not overly monolithic.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=1523s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>To avoid blocking the main thread, I perform expensive tasks on background threads. During launch this causes a lot of thread hops. How expensive is frequent thread hopping compared to thread blocking, and is there a better solution for performance?</h2><p>Thread hopping has overhead, but if you are not doing it excessively, that overhead is usually small. It becomes a concern when it happens extremely frequently.</p><p>The bigger issue during launch is often doing too much work too early, or starting background work and then making the main thread wait for it before the first frame. That still blocks the user experience even if the work happens on background threads.</p><p>Focus on the minimum data needed to draw the first useful frame. Defer non-critical work until after launch. Cache previous results when possible. For example, if you fetch A/B test configuration during launch, consider using the cached result first and updating later.</p><p>Use Instruments to measure the problem. System Trace can show context switch counts and blocked thread states. Xcode Organizer can also show real-world launch metrics and call stacks for slow launches in shipped apps.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=1688s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>How should developers measure app launch time? Should they inspect low-level APIs to see when the process was created?</h2><p>Use Apple&#8217;s tools instead of trying to infer launch time yourself from low-level APIs. MetricKit and Xcode Organizer measure launch efficiently and include parts of launch that your app process cannot measure on its own.</p><p>For example, they can account for the interval from when the user taps the app icon to when the first rendered screen appears. Your app code cannot directly measure the moment before your process exists.</p><p>This is the same kind of launch measurement Apple uses for its own apps. It avoids adding extra measurement overhead and gives you a user-focused view of launch performance.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=2045s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Besides background tasks, what is the most common silent battery killer in SwiftUI? How much power does view over-invalidation actually drain, and what is the best Instruments workflow to catch it before release?</h2><p>View over-invalidation can be a serious silent battery issue because it may not produce visible changes. The screen can look exactly the same while the CPU keeps recreating views in the background.</p><p>The key is to minimize unnecessary redraws. Keep dependencies precise, flatten overly deep hierarchies where appropriate, and avoid repeatedly dispatching background work just to fetch data for UI that could have been cached or computed once.</p><p>Use the SwiftUI instrument to find unnecessary view updates. Pair that with Power Profiler to understand the energy cost. If the extra invalidation is CPU-heavy, it can show up as foreground energy drain.</p><p>The larger principle still applies: cache when possible, avoid repetitive work, and measure before optimizing.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=2148s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Are there performance improvements for very large lists and table views in SwiftUI for macOS 27? What are best practices for making long SwiftUI lists and tables work well with tens or hundreds of thousands of items?</h2><p>For very large lists, keep the list structure as stable as possible. If cells constantly change size, that can force SwiftUI to recalculate what appears at each scroll offset. Stable row sizes are easier for SwiftUI to cache and reason about.</p><p>Use lazy data structures and lazy SwiftUI containers where appropriate. Also move filtering and data preparation into the model layer rather than putting conditionals and transformations directly inside <code>ForEach</code>. Give SwiftUI the final data it needs to display, not a giant unfiltered set it has to chew through during rendering.</p><p>Batch work and load only the visible or near-visible data. The same idea used for launch performance applies here: what is the minimum information needed for the next useful UI update?</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=2240s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>I use <code>AnyView</code> for type erasure in several places. How expensive is it in practice? Is there a concrete threshold beyond which <code>AnyView</code> becomes a problem, or is avoiding it premature optimization?</h2><p><code>AnyView</code> and type erasure do add some overhead when creating views, so it is reasonable to avoid them when they are easy to avoid.</p><p>But do not contort your design just to remove <code>AnyView</code> everywhere. If it becomes measurable, then address it. Otherwise, you may spend time optimizing something that does not matter for your app.</p><p>This is a general performance principle: measure first. Some APIs have costs, but they exist for a reason. If using a type-erased view makes a design cleaner and does not show up in profiling, the time may be better spent elsewhere.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=2383s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>MetricKit state reporting and crash report extensions are new and noteworthy this year. Are there any other headlining developer tools worth looking at?</h2><p>Xcode Organizer received important improvements, especially around Metric Goals. Metric Goals help you understand how your app compares to similar apps, which is useful because raw numbers are often hard to judge in isolation.</p><p>For example, a video app may naturally use more power than a simple utility app. Metric Goals give you a more meaningful baseline by comparing against apps in similar categories.</p><p>State reporting is also worth adopting. Combined with MetricKit, it lets you slice metrics by app state and identify where power, launches, hitches, or hangs are poor. That gives you a much clearer target for optimization.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=2518s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>If there is one thing developers should try from the new tools this year, what should it be?</h2><p>Metric Goals are a strong starting point because they show how your metrics compare with similar apps. That helps you understand whether power, launch time, hitches, or hangs are genuinely worse than expected.</p><p>State reporting is the second big one. It lets you connect metrics to specific app states, so you can see where performance or power is getting worse. Together, Metric Goals and state reporting help move performance work from vague concern to targeted investigation.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=2725s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Swift performance is something I&#8217;m genuinely passionate about and want to go deep on beyond WWDC sessions and Swift Evolution proposals. What does the pathway look like for building real deep expertise?</h2><p>Experience is the main path. Build things, profile them, and inspect what actually happens. Instruments gives you many perspectives, including Time Profiler, SwiftUI instrument, and other templates that reveal what frameworks are doing behind the scenes.</p><p>For deeper Swift performance expertise, study how the standard library and open-source Swift packages are implemented. Look at benchmarks, inspect generated behavior, and experiment with changes. Combine that with Instruments so your mental model is grounded in measurements, not assumptions.</p><p>The important habit is to form hypotheses and then test them. Swift performance work is not only about knowing APIs. It is about understanding where time and energy are actually spent, then using the right tool or code change to improve the real bottleneck.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=2808s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>If I have a newer device but want to make sure performance is good on older devices, what should I do?</h2><p>A simple first step is to turn on Low Power Mode. It reduces CPU performance to save battery, which can reveal issues that you may not see on a newer device running at full performance.</p><p>Use physical devices for profiling when possible. Simulator performance depends on the Mac, not the simulated device model, so it is not a reliable way to judge device performance.</p><p>Condition inducers can also help. They let you artificially induce system conditions such as thermal pressure without physically heating the device. Field data from MetricKit and Xcode Organizer is also valuable because it shows performance across real users, real devices, and real conditions.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=3163s">&#9201;&#65039;Time code</a></p><div><hr></div><h2>Does using a lot of <code>@Environment</code> properties in a large SwiftUI app have any performance impact?</h2><p>Reading values from the environment is not necessarily expensive by itself. The main performance issue is environment churn.</p><p>If values are placed in the environment and read by many views, that can be fine when they do not change frequently. Problems start when those environment values update often. Then every view that reads from the environment has to reevaluate whether something changed.</p><p>So the issue is not simply &#8220;many environment values.&#8221; The issue is frequently changing environment values across a deep view hierarchy. Use the SwiftUI instrument to verify whether that churn is actually causing rendering or update performance issues.</p><p><a href="https://www.youtube.com/watch?v=Lhv33ipQERc&amp;t=3542s">&#9201;&#65039;Time code</a></p><div><hr></div><h2><code>&#127942;</code>Acknowledgments</h2><p>A huge thank-you to everyone who joined and shared practical, performance-focused questions throughout the session. Your questions made the discussion useful for developers working on launch time, SwiftUI rendering, background work, MetricKit, Xcode Organizer, Instruments, power usage, and real-world field diagnostics.</p><p>The uploaded transcript does not include stable attendee nicknames for most questions, so the acknowledgments avoid inventing names. Question acknowledgments: the online WWDC audience who submitted and upvoted the Power and Performance questions.</p><p>Finally, a heartfelt thank-you to Cole, Terry, Yanni, Kasper, Kunal, and Marco for leading the session, sharing practical guidance, and explaining how to approach power and performance with measurement-first thinking.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://antongubarenko.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Anton&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>