Swift Dev Journal's Avatar

Swift Dev Journal

@swiftdevjournal.mastodon.world.ap.brid.gy

I develop Mac and iOS apps (Phel, Bartleby, AM Pages) in Swift using SwiftUI and AppKit. I also write about app development in Swift at Swift Dev Journal. πŸŒ‰ bridged from ⁂ https://mastodon.world/@swiftdevjournal, follow @ap.brid.gy to interact

85
Followers
0
Following
241
Posts
06.06.2024
Joined
Posts Following

Latest posts by Swift Dev Journal @swiftdevjournal.mastodon.world.ap.brid.gy

Add an Open Recent Menu to a SwiftUI app Why would you need to add an Open Recent menu? The most common reason is you created an app that doesn’t use the document architecture, and you want a way for your app’s users to access recent items. Adding an Open Recent menu requires you to do the following things: * Use the `NSDocumentController` class to track recent items. * Add an `@Observable` class to hold the recent items so SwiftUI can update the Open Recent menu when its contents change. ## Using `NSDocumentController` to track recent items The name `NSDocumentController` implies that it works with `NSDocument`. However, the parts of `NSDocumentController` that deal with the Open Recent menu require only an array of URLs. You can use `NSDocumentController` without creating a document app. Use the `shared` instance to access the standard document controller. NSDocumentController.shared Use the `recentDocumentURLs` property to access the URLs of the recent items and fill the Open Recents menu. Call the `noteNewRecentDocumentURL` function to update the recent items after opening or creating an item. Call the `clearRecentDocuments` function to clear the recent items list and clear the Open Recent menu. ## Initial version of the Open Recent menu An initial version of an Open Recent menu looks like the following code: struct OpenRecentMenu: View { @Environment(\.openWindow) private var openWindow var body: some View { Menu("Open Recent") { ForEach(NSDocumentController.shared. recentDocumentURLs, id: \.self) { url in Button(url.lastPathComponent) { // Item is a class in your app. let itemToOpen = Item(location: url) openWindow(value: itemToOpen) NSDocumentController.shared. noteNewRecentDocumentURL(url) } } Divider() Button("Clear Menu") { NSDocumentController.shared. clearRecentDocuments(nil) } } } } The code creates the Open Recent menu and fills it with recent items. There is one big problem. The Open Recent menu doesn’t update until you restart the app. The reason the menu doesn’t update is SwiftUI doesn’t automatically update the menu when the shared document controller’s array of recent items changes. To get the menu to update, you must add an `@Observable` class that holds the recent item URLs and pass that class to the menu view. ## Create the `@Observable` class The class has two requirements. First, it needs a property that holds the URLs of the recent items. Second, it needs a function to update the array from the shared document controller. @Observable class RecentItems { @MainActor static let shared = RecentItems() var items: [URL] = [] init(items: [URL]) { self.items = items } @MainActor func refresh() { let docControllerRecents = NSDocumentController. shared.recentDocumentURLs if docControllerRecents != items { items = docControllerRecents } } } Supply the value `NSDocumentController.shared.recentDocumentURLs` to the `RecentItems` initializer to fill the Open Recent menu when your app launches. When you open or add an item in your app, call the `refresh` function to update the Open Recent menu. ## Add the `@Observable` class to the Menu To use your `@Observable` class in the menu, you must add a `@State` property for the class to the App struct. Pass the value to the menu using a binding. Use the array in your `@Observable` class to fill the Open Recent menu. The following code shows the updated Open Recent menu: struct OpenRecentMenu: View { @Environment(\.openWindow) private var openWindow @Binding var recents: RecentItems var body: some View { Menu("Open Recent") { ForEach(recents.items, id: \.self) { url in Button(url.lastPathComponent) { let item = Item(location: url) openWindow(value: item) NSDocumentController.shared. noteNewRecentDocumentURL(url) recents.refresh() } } Divider() Button("Clear Menu") { NSDocumentController.shared. clearRecentDocuments(nil) recents.refresh() } } } }

The following article shows how to add an Open Recent menu to a SwiftUI app:

https://swiftdevjournal.com/posts/open-recent-menu/

#SwiftUI

04.03.2026 19:16 πŸ‘ 1 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Audio Descriptions - Wesley de Groot Audio descriptions provide narration of visual elements in video content, making it accessible to blind and low vision users. In this post, we'll explore what audio descriptions are, how to detect user preferences for them, and how to implement audio description support in your SwiftUI apps. What are Audio Descriptions? Audio descriptions (also called video descriptions or descriptive narration) are audio tracks t...

Audio Descriptions https://wesleydegroot.nl/blog/audio-descriptions #Accessibility #SwiftUI

03.03.2026 07:00 πŸ‘ 0 πŸ” 1 πŸ’¬ 0 πŸ“Œ 0
Measure App Launch Time with Instruments Take the following steps to measure your app’s launch time with Instruments: 1. Press Cmd-I or choose Product > Profile to profile your app. 2. Select the App Launch template when Instruments launches. 3. Click the Choose button. 4. Click the Record button to start profiling. 5. Select the item with the name of your app from the timeline pane. 6. Press Cmd-4 to open the App Lifecycle section. The App Lifecycle section lists the app’s launch steps and how long each step took. ## Do you want to learn more about Instruments? I wrote a book, _Profiling Swift Apps_ , that shows you how to use Instruments to find and fix problems in your code. The book will help you make apps that run faster and use less memory. You can learn more about the book and download a sample at the following link: Profiling Swift Apps page

Wondering how long your app takes to launch? The following article shows how to use Instruments to measure your app's launch time:

https://swiftdevjournal.com/posts/measure-app-launch-time/

#Xcode

02.03.2026 19:51 πŸ‘ 0 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Find the SwiftUI Views that Update the Most Using Instruments Β· Swift Dev Journal

The following article shows how to use the new SwiftUI instrument to find the views in your app that update the most:

https://swiftdevjournal.com/posts/swiftui-frequent-view-updates/

#SwiftUI #Xcode

27.02.2026 19:32 πŸ‘ 1 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Preview
Why Your @Observable Class init() Runs Multiple Times in SwiftUI β†’ Livsy Code Greetings, traveler! SwiftUI encourages a lightweight view layer. Views are value types, rebuilt frequently, and expected to be cheap. This mental model becomes tricky when you start storing reference types in @State, especially after adopting the Observation framework (@Observable). A common surprise looks like this: struct FeatureView: View { @State private var viewModel = FeatureViewModel()

The following article explains why an Observable class's init runs multiple times in SwiftUI:

https://livsycode.com/swiftui/why-your-observable-class-init-runs-multiple-times-in-swiftui/

#SwiftUI

24.02.2026 18:54 πŸ‘ 1 πŸ” 0 πŸ’¬ 0 πŸ“Œ 1
Preview
Creating Maps in SwiftUI apps with MapKit Learn how to integrate Maps using MapKit in modern iOS applications.

The following article shows how to use MapKit to create maps in SwiftUI apps:

https://www.createwithswift.com/creating-maps-in-swiftui-apps-with-mapkit/

#SwiftUI

23.02.2026 20:14 πŸ‘ 2 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Preview
The 4-Step Process I Use to Create SwiftUI Animations Stop throwing .animation() modifiers everywhere and hoping for the best. Here's the systematic process I use to build polished animations that actually work.

The following article shows a process to create SwiftUI animations:

https://www.swiftdifferently.com/blog/swiftui/swiftui-animation-with-example

#SwiftUI

20.02.2026 19:43 πŸ‘ 2 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Original post on mastodon.world

I tried using SwiftUI's new support for rich text in TextEditor. It's nowhere near a replacement for NSTextView on Mac.

You have to open the ruler from the Format menu to show rich text formatting controls. The controls are limited compared to NSTextView's inspector.

The worst issue is […]

19.02.2026 18:55 πŸ‘ 0 πŸ” 0 πŸ’¬ 1 πŸ“Œ 0
James Dempsey (@jamesdempsey@mastodon.social) Looking to level up your developer skills in 2026? My App Performance and Instruments course kicks off next week! This will likely be the only run of the course this half of the year - so if you are interested, I hope you can join us. Click through for full course details, testimonials from past students, and enrollment info. https://swift-virtuoso.com (Please boost to help spread the word!)

If you're looking for a course on learning Instruments, take a look at the course details. https://mastodon.social/@jamesdempsey/116092908262340740

18.02.2026 19:02 πŸ‘ 0 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Wesley de Groot πŸ₯· (@0xWDG@mastodon.social) Voice Control https://wesleydegroot.nl/blog/voice-control #Accessibility #SwiftUI

This article provides a nice introduction to supporting Voice Control in SwiftUI apps. https://mastodon.social/@0xWDG/116084677459556586

17.02.2026 18:41 πŸ‘ 3 πŸ” 1 πŸ’¬ 0 πŸ“Œ 0
Preview
Building a SwiftUI Toast in 5 Steps β†’ Livsy Code Greetings, traveler! SwiftUI still doesn’t provide a native toast component. Alerts and sheets exist, but both are modal by design. A toast solves a different problem: it delivers short-lived feedback without interrupting the user’s flow. In this article, I’ll walk through a practical way to implement a toast in SwiftUI. The solution is lightweight, reusable,

The following article shows how to create a Toast component in SwiftUI:

https://livsycode.com/swiftui/building-a-toast-component-in-swiftui/

#SwiftUI

16.02.2026 19:01 πŸ‘ 1 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Preview
Taking First Steps into Metal Shaders Learn the basics of Metal with SwiftUI to take your first steps on using shaders in your app UI.

The following article introduces Metal shaders and shows how to use them in SwiftUI apps:

https://www.createwithswift.com/taking-first-steps-into-metal-shaders/

#SwiftUI

13.02.2026 18:44 πŸ‘ 7 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Original post on mastodon.world

SwiftUI instrument tip: take the following steps to find the code causing long updates:

1. Right-click on a red or orange bar in the graph.
2. Choose Set Inspection Range.
3. Switch to the Time Profiler instrument.
4. Hide System Libraries.
5. Double-click a function to see the lines of code […]

12.02.2026 19:29 πŸ‘ 1 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Morphing Sheets Out of Buttons in SwiftUI – SerialCoder.dev

The following article shows how to morph a sheet directly from a button in a SwiftUI app:

https://serialcoder.dev/text-tutorials/swiftui/morphing-sheets-out-of-buttons-in-swiftui/

#SwiftUI

10.02.2026 19:11 πŸ‘ 0 πŸ” 1 πŸ’¬ 0 πŸ“Œ 0
Profiling Swift Apps Book Β· Swift Dev Journal

If you have trouble figuring out what Instruments is reporting, my Profiling Swift Apps book can help.

https://swiftdevjournal.com/instruments-book/ https://mastodon.social/@alexsteinerde/116029192259707294

09.02.2026 19:22 πŸ‘ 0 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Supporting SwiftUI Sidebar Selection with Multiple Data Types When handling the sidebar selection in a SwiftUI app, the usual approach is to add a `@State` property to the view to store the selection. The code looks similar to the following code: @State private var selection: Chapter? = nil The usual approach works well if all the items in the sidebar have the same data type. What do you do if the sidebar items have different data types? Supporting selection with multiple data types involves the following tasks: * Create an enum for the sidebar selection. * Use the enum you create as the data type for the selection. * Add a `.tag` modifier to each list item that holds the item’s data type and value. ## Creating the enum Create an enum for the sidebar selection with a case for each possible data type a sidebar item can have. As an example I’m going to show code for an app I’m currently making, a Mac GUI client for the Jujutsu version control system. The app’s sidebar has multiple items for controlling what appears in the list of changes (commits). The selection can be either a change category (all changes, mutable changes, my changes) or a bookmark (branch). Selecting a bookmark shows its changes. The following code shows the enum for the sidebar selection: enum SidebarSelection: Hashable, Sendable { case change(category: ChangeCategory) case bookmark(bookmark: Bookmark) } enum ChangeCategory: CaseIterable { case allChanges case mutableChanges case myChanges func stringValue() -> String { switch(self) { case .allChanges: return "All Changes" case .mutableChanges: return "Mutable Changes" case .myChanges: return "My Changes" } } } struct Bookmark: Equatable, Hashable, Codable, Sendable { // Other properties removed for clarity. var name: String static func == (lhs: Bookmark, rhs: Bookmark) -> Bool { lhs.name == rhs.name } } ## Using the enum for the selection In the sidebar view, add a property to store the selection. The data type is the enum you created. @State private var selection: SidebarSelection? ## Adding the .tag modifier Each list item in the sidebar needs a `.tag` modifier so SwiftUI knows what the item represents. The value of the modifier is one of the sidebar selection enum’s cases. You must also supply any additional data the enum case requires. The following code shows a sidebar list with sections for change categories and bookmarks: List(selection: $selection) { Section(header: Text("Changes")) { ForEach(ChangeCategory.allCases, id:\.self) { category in Text(category.stringValue()) .tag(SidebarSelection.change(category: category)) } } Section(header: Text("Bookmarks")) { ForEach(bookmarks, id:\.name) { bookmark in Text(bookmark.name) .tag(SidebarSelection.bookmark(bookmark: bookmark)) } } }

The following article shows how to support SwiftUI sidebar selection when the sidebar has multiple types of items:

https://swiftdevjournal.com/posts/sidebar-selection/

#SwiftUI

05.02.2026 18:51 πŸ‘ 2 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Preview
Objectively Better, Observably Trickier The Observation Framework is great... once you figure out how it actually works

The following article talks about problems you may encounter when converting existing code from ObservableObject to the Observation framework :

https://captainswiftui.substack.com/p/objectively-better-observably-trickier

#SwiftUI

04.02.2026 19:53 πŸ‘ 2 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0

TIL: the URL NSSavePanel returns for a folder does not include a trailing slash while SwiftUI's fileImporter includes the trailing slash.

#MacDev

03.02.2026 20:54 πŸ‘ 2 πŸ” 0 πŸ’¬ 1 πŸ“Œ 0
Original post on mastodon.world

Instruments tip: take the following steps to find the code in your app causing a hang:

1. Right-click on the hang in the graph
2. Choose Set Inspection Range to focus on the hang
3. Switch to the Time Profiler instrument
4. Click the Call Tree button at the bottom of the window
5. Select the […]

30.01.2026 18:54 πŸ‘ 0 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Preview
Sharing content among apps using AppEntity and Transferable protocol A fundamental characteristic of Apple’s ecosystem user experience is that everything feels like being in one connected system no matter on which of your Apple devices you are operating: think about the capability of copying something from your mac and paste it effortlessly on your iPhone, for example, or

The following article shows how to share content among iOS and Mac apps:

https://www.createwithswift.com/sharing-content-among-apps-using-appentity-and-transferable-protocol/

#iOSDev #MacDev

27.01.2026 19:05 πŸ‘ 0 πŸ” 1 πŸ’¬ 0 πŸ“Œ 0
Find the SwiftUI Views that Update the Most Using Instruments Β· Swift Dev Journal

The following article shows how to use the new SwiftUI instrument to find the views in your app that update the most:

https://swiftdevjournal.com/posts/swiftui-frequent-view-updates/

#SwiftUI #Xcode

26.01.2026 18:57 πŸ‘ 1 πŸ” 1 πŸ’¬ 0 πŸ“Œ 0
Original post on mastodon.world

SwiftUI instrument tip: take the following steps to find the code causing long updates:

1. Right-click on a red or orange bar in the graph.
2. Choose Set Inspection Range.
3. Switch to the Time Profiler instrument.
4. Hide System Libraries.
5. Double-click a function to see the lines of code […]

22.01.2026 18:57 πŸ‘ 1 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Preview
How to Avoid Double Updates When Filtering SwiftUI TextField Input β†’ Livsy Code Greetings, traveler! SwiftUI makes it easy to react to text input. The common approach is to validate or format the string inside onChange and then write the processed value back into the same binding. It works, it is quick to implement, and it is often enough. Sometimes, the processing step matters more than the UI.

The following article shows how to prevent SwiftUI text fields from updating twice when filtering the text input:

https://livsycode.com/swiftui/how-to-avoid-double-updates-when-filtering-swiftui-textfield-input/

#SwiftUI

21.01.2026 17:11 πŸ‘ 0 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Preview
Providing access to premium features with StoreKit 2 Learn how to build a tiered subscription system and gate premium features in a SwiftUI app using StoreKit 2.

Article link: https://www.createwithswift.com/providing-access-to-premium-features-with-storekit-2/ https://mastodon.social/@n0rthk1n9/115929064183477036

20.01.2026 21:13 πŸ‘ 0 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Reducing the Number of .sheet Modifiers in Your SwiftUI Views Β· Swift Dev Journal

If you find that your SwiftUI views have too many .sheet modifiers, the following article shows a way to reduce the number of modifiers:

https://swiftdevjournal.com/posts/reducing-sheet-modifiers/

#SwiftUI

20.01.2026 19:03 πŸ‘ 2 πŸ” 1 πŸ’¬ 0 πŸ“Œ 0
Supporting SwiftUI Sidebar Selection with Multiple Data Types When handling the sidebar selection in a SwiftUI app, the usual approach is to add a `@State` property to the view to store the selection. The code looks similar to the following code: @State private var selection: Chapter? = nil The usual approach works well if all the items in the sidebar have the same data type. What do you do if the sidebar items have different data types? Supporting selection with multiple data types involves the following tasks: * Create an enum for the sidebar selection. * Use the enum you create as the data type for the selection. * Add a `.tag` modifier to each list item that holds the item’s data type and value. ## Creating the enum Create an enum for the sidebar selection with a case for each possible data type a sidebar item can have. As an example I’m going to show code for an app I’m currently making, a Mac GUI client for the Jujutsu version control system. The app’s sidebar has multiple items for controlling what appears in the list of changes (commits). The selection can be either a change category (all changes, mutable changes, my changes) or a bookmark (branch). Selecting a bookmark shows its changes. The following code shows the enum for the sidebar selection: enum SidebarSelection: Hashable, Sendable { case change(category: ChangeCategory) case bookmark(bookmark: Bookmark) } enum ChangeCategory: CaseIterable { case allChanges case mutableChanges case myChanges func stringValue() -> String { switch(self) { case .allChanges: return "All Changes" case .mutableChanges: return "Mutable Changes" case .myChanges: return "My Changes" } } } struct Bookmark: Equatable, Hashable, Codable, Sendable { // Other properties removed for clarity. var name: String static func == (lhs: Bookmark, rhs: Bookmark) -> Bool { lhs.name == rhs.name } } ## Using the enum for the selection In the sidebar view, add a property to store the selection. The data type is the enum you created. @State private var selection: SidebarSelection? ## Adding the .tag modifier Each list item in the sidebar needs a `.tag` modifier so SwiftUI knows what the item represents. The value of the modifier is one of the sidebar selection enum’s cases. You must also supply any additional data the enum case requires. The following code shows a sidebar list with sections for change categories and bookmarks: List(selection: $selection) { Section(header: Text("Changes")) { ForEach(ChangeCategory.allCases, id:\.self) { category in Text(category.stringValue()) .tag(SidebarSelection.change(category: category)) } } Section(header: Text("Bookmarks")) { ForEach(bookmarks, id:\.name) { bookmark in Text(bookmark.name) .tag(SidebarSelection.bookmark(bookmark: bookmark)) } } }

The following article shows how to support SwiftUI sidebar selection when the sidebar has multiple data types:

https://swiftdevjournal.com/posts/sidebar-selection/

#SwiftUI

16.01.2026 20:04 πŸ‘ 2 πŸ” 0 πŸ’¬ 1 πŸ“Œ 0
stackotter (@stackotter@mastodon.social) As SwiftCrossUI and Swift Bundler have grown, it’s become clear that they deserve to live under their own organisation. For that reason, I’ve created the moreSwift organisation and transferred SwiftCrossUI, Swift Bundler and a few other related projects from my personal account to the organisation. β€œCreate your next app with moreSwift” πŸ˜‰ https://github.com/moreSwift

SwiftCrossUI looks like an interesting project if you want to build Windows and Linux apps using a SwiftUI-like syntax. https://mastodon.social/@stackotter/115903981719529756

16.01.2026 19:21 πŸ‘ 2 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Original post on mastodon.world

Instruments tip: take the following steps to find the code in your app causing a hang.

1. Right-click on the hang in the graph
2. Choose Set Inspection Range to focus on the hang
3. Switch to the Time Profiler instrument
4. Click the Call Tree button at the bottom of the window
5. Select the […]

14.01.2026 18:50 πŸ‘ 0 πŸ” 1 πŸ’¬ 0 πŸ“Œ 0
Original post on mastodon.world

Do you have performance problems in your app, such as the app running slow or using tons of memory? Do you struggle to find the cause of those problems?

If you answered Yes to both questions, my Profiling Swift Apps book can help. The book shows you how to use Instruments to find performance […]

13.01.2026 20:01 πŸ‘ 2 πŸ” 0 πŸ’¬ 0 πŸ“Œ 0
Preview
Pasi Salenius (@pasi@infosec.exchange) Attached: 1 image I’m happy enough with the HTML help bundles generated by my HelpBooks tool. The table of contents in the HTML sidebar is keyboard navigable, resizable and allows collapsing sections. Already added this to my dev Proxygen app and it’s nice. It’s all offline. The β€œMavericks” theme pictured in the video is the best but there’s also β€œModern” and β€œTiger”. None of the toolbar items work (back/forward navigation, home, search) but that’s okay I think. https://github.com/PasiSalenius/HelpBooks #appkit #macdev

If you're looking for a tool to create help books for Mac apps, check out the GitHub page. https://infosec.exchange/@pasi/115886959182785860

13.01.2026 18:57 πŸ‘ 0 πŸ” 1 πŸ’¬ 0 πŸ“Œ 0