❌

Reading view

Getting a File Path From a Swift URL

Seth Willits (2024, bug):

There’s a deprecation warning in Xcode for URL.path that reads:

WARNING: path will be deprecated in a future version of macOS: Use path(percentEncoded:) instead

The problem is something like this:

Bundle.main.url(forAuxiliaryExecutable: "tool")!.path

… which returns the expected file path (ex: /Applications/MyApp.app/Contents/tool)

would be quickly rewritten as suggested to:

Bundle.main.url(forAuxiliaryExecutable: "tool")!.path(percentEncoded: false)

… which simply returns tool, because the URL returned is relative to a base URL.

[…]

I’ve always found it not-completely-obvious to newcomers how to get a standard file path string from a file URL and this only makes it more confusing.

There are at least three issues here:

  1. url.path returns an absolute path, but url.path(percentEncoded: false) returned a relative path as of his writing. I tested this on macOS 26, and now it returns an absolute path. The documentation now says, “This function will resolve against the base URL.” It seems the behavior of the method changed without it being documented when, so be careful if you’re deploying to a mix of OS versions.

  2. percentEncoded has a default value of true, whereas path did not return an encoded string. In other words, url.path() and url.path are completely different. So this is another case where Apple updated the API but flipped the default—a good way to introduce bugs.

  3. It’s not obvious how to get the full file system path out of a URL. With NSURL, url.path was natural and did the right thing. Now, the URL equivalent is deprecated.

    The natural replacement, url.path(), is wrong. So is Xcode’s recommendation of url.(percentEncoded: false).

    url.absoluteURL.path(percentEncoded: false) is correct but verbose.

    url.absoluteURL.standardizedFileURL.path(percentEncoded: false) is possibly better but even more verbose.

    FilePath(url)?.string uses a newer API but gives you an optional, even though for a file URL it should never fail.

    This seems like such basic functionality, but there’s no API that’s the obvious right choice, concise, and ergonomic.

Previously:

  •  

EagleFiler 1.9.22

EagleFiler 1.9.22 is a maintenance release of my Mac file/note organizer and e-mail archiving app. This version works around various bugs in macOS 27, adds capture support for the Thorium Web browser, and improves importing from Mariner Paperless.

  • macOS 27 broke several things with drag and drop out of Apple Mail. Simply trying to read a URL from the pasteboard will cause a hang while it waits forever for the pasteboard server (FB24803817). The same thing happens when using PasteboardSetPasteLocation() and reading kPasteboardTypeFileURLPromise directly, which I was doing (instead of using newer API) to work around bugs in older versions of macOS. EagleFiler now uses NSFilePromiseReceiver for drags from Mail on macOS 27, which works better, but I also had to work around a bug where Mail would promise superfluous files for which the reader callback was never invoked at all.

  • macOS 27 also seems to include various regressions when reading PDF and Word files, producing invalid strings containing NUL characters. Also, displaying certain PDF files worked fine on macOS 26 but now crashes.

  • I also ran into (and worked around) a bug where macOS 27’s NSTextView would get into an infinite layout loop when displaying an attributed string that included images.

  • Drag and drop from Airmail is still an issue. When using the newer drag APIs, it will often hang Airmail or not produce a file, and this also happens with other apps like Finder as the destination. EagleFiler works around this using older APIs with Airmail and tries to report a helpful error when there’s trouble. Single-message drags work best.

  • I’ve also been investigating a problem where saving a file with a colored tag in iCloud Drive will, a few seconds later, change the color to gray, but I don’t have a solution for this.

Previously:

  •  

SpamSieve 3.3.2

SpamSieve 3.3.2 is an update of my Mac e-mail spam filter that improves remote training, can export more rule information, and improves uninstallation, help, and more. The most significant news is that Microsoft has changed plans again. They will no longer be preventing users from continuing to use Legacy Outlook and in fact will keep it available for download as part of the combined Outlook app. This gives more time to adapt to their change in plans for AppleScript. Exchange (EWS) support remains an issue. Microsoft is still planning to cut off Legacy Outlook users, and Apple has yet to announce when Mail will support Graph. So far, I’ve not heard that it’s enabled in the macOS 27.2 beta.

We’re participating in a seasonal festival of artisanal software called SummerFest. For a limited time, you can get a 25% discount on new purchases of SpamSieve, EagleFiler, and other top Mac apps from our indie developer friends.

Some interesting engineering issues were:

  • Updating NSWorkspace APIs introduced a problem because with the old launchApplication(at:options:), the .withErrorPresentation option is off by default, whereas with the newer openApplication(at:configuration:completionHandler:), the promptsUserIfNeeded option is on by default.

  • Previously, Core Data would strip leading BOMs from NSStrings when saving to a SQLite database. With macOS 27, this happens for Swift Strings, too.

  • I have lots of unit tests that check for memory leaks. These caught a change where addPersistentStore(type:configuration:at:options:) now seems to return an autoreleased store. Without adding a pool, it looked like there was a leak.

  • Also, the tests were finding lots of “leaks” because KVO was retaining NSTabView, which retains a controller. Previously, XCTestCase.waitForExpectations(timeout:) would spin the run loop, and everything would get cleaned up. With Xcode 27 and macOS 27, I need to manually spin the run loop before waiting for the expectations.

  • During a software update, macOS may decide to reload the Dock icon. The application package no longer exists because it’s been replaced with a new version. This wasn’t a problem before because SpamSieve had been drawing to an image in memory and setting that as the Dock icon. Now, with the Liquid Glass–imposed removal of custom Dock icons, macOS tries to load the icon from disk, and rather than handling errors gracefully it will crash. I fixed this by setting an image with a memory representation before starting a software update.

  • SpamSieve 3.3.1 introduced a crash affecting a small but significant number of users when doing a Core Data fetch of a large number of objects. The private [_PFManagedObjectReferenceQueue _processReferenceQueue:] method was seemingly releasing an object that had already been released. What’s odd is that, as far as I can tell, none of the related app code had changed since the previous version, yet suddenly crashes started happening all the way from macOS 12 through macOS 27. If I had to guess, this was triggered by upgrading from Xcode 26.2 to Xcode 26.6. Maybe Swift’s ARC optimizations are doing something subtly different?

    The crash was triggered by an autorelease pool that I had inserted to promptly clean up any temporary objects after a fetch. (The actual fetched objects were returned and used outside of the pool.) Interestingly, both Gemini and ChatGPT were convinced that this is a well-known exception to standard memory management rules. They said it’s never safe to use managed objects outside of a pool they were fetched in because they depend on internal Core Data objects that the pool will have released. I was not able to find any basis for this “belief,” but it was easy enough to test. As expected, removing the pools (during the beta cycle) just made the same crashes happen slightly later.

    I think there’s probably something wrong in Core Data’s internal bookkeeping, but this does not seem to be a popular crash (and I’ve never seen it on any of my Macs), so my code must be doing something uncommon to trigger it. My current best guess is that it was related to calling refreshAllObjects() after saving. (I bet there’s some fancy bookkeeping to make that efficient.) I was doing this throughout the app to break retain cycles so that unused objects could be deallocated. But it wasn’t necessary in this particular case because the entity being fetched has no relationships. So far, removing the refresh seems to have stopped the crashes, but I won’t know for sure until more people have been using this version for a while.

Previously:

  •  

Golden Gate Release Candidate

Juli Clover:

The release candidate is the final version of macOS Golden Gate that developers and beta testers will get before the software sees a public launch.

Joe Rossignol (Reddit):

Apple this week announced that macOS 27, also known as macOS Golden Gate, will be released to all users with a compatible Mac on Monday, September 14.

iOS 27, iPadOS 27, watchOS 27, tvOS 27, and visionOS 27 will be released on the same day.

Jeff Johnson:

I would like to note two bugs that I reported during the beta period that remain unfixed in the release candidates, and barring a last minute miraculous reprieve, will remain unfixed in the public releases on Monday. This is disappointing, because I thought the point of the betas was for Apple to fix the bugs found by beta testers. While these two bugs are not destructive—do not involve data loss or security issues, for example—they nonetheless did not exist in iOS 26 and macOS 26, so in this respect, Apple’s updates are making their software worse for users.

[…]

The AppleScript run by the test app requires Automation permission, so macOS shows a permission prompt. […] It actually doesn’t matter whether you select Allow or Don’t Allow! […] Either way, just selecting something in the automation permission prompt seems to trigger the bug, causing macOS to wrongly consider the app to be running in the background.

Paul Kafasis:

Unfortunately, Apple’s forthcoming tvOS 27 and HomePod OS 27 updates contain a critical bug that prevents Apple TVs and HomePods from playing AirPlay streams sent by Airfoil. If your devices update to the OS 27 versions, Airfoil will no longer be able to stream to them.

Ron Elemans:

FB24067183 Changing selection in NSTableView by moving the mouse and holding down left button, does not work anymore[…]

Kevin C:

Font Book has been crashing since beta 4 when resizing the Inspector or Sidebar. This was a further degradation over a related bug in Tahoe. So far it seems specific to Font Book.

Previously:

  •  

NSToolbar in Golden Gate

John Brayton:

NSTrackingSeparatorToolbarItem adds a white band over the top of the leading split view panes when in full screen mode on macOS 27 [beta 3]. That white band appears to have the height of the toolbar.

He says this was fixed in Beta 4.

John Brayton:

macOS 27 developer beta 5 (26A5406e) introduces a bug that causes a white bar to appear over window content if the window’s toolbar has an NSTrackingSeparatorToolbarItem. I filed FB24266969 with Apple describing this.

Steve Troughton-Smith:

NSSearchToolbarItem has been screwed last minute in Catalyst with less than a month to go? Cool, cool…

That’s the kind of thing that can halt my release plans entirely 🫠

Ron Elemans:

Also screwed up in AppKit, with the macOS 27 beta 5 release.

Also, the titlebarSeparatorStyle setting seems to be ignored. Toolbars in beta 5 always have a separator line and a blurred slightly lighter background.

Weirdly enough Apple’s own apps don’t have these issues.

John Brayton:

In macOS 27 developer beta 5, search fields in toolbars (NSSearchToolbarItem instances) have their placeholder text, search strings, and magnifying glass icons vertically off-center. I reported this as FB24286690.

Mario Guzmán:

Beta 6 also fixes the UI issues with NSSearchToolbarItem. Elements are now re-aligned again, the recents menu is in a good position, and the focus ring is perfectly outlining the entire bounds. :D

Previously:

  •  

NSPasteboard Crashes When Handling File Promises

Wade Tregaskis:

NSPasteboard mutates itself simultaneously from the main thread and the global concurrent Dispatch pool, w.r.t. to its internal type cache. This is surprisingly trivial to reproduce (sample code below) by just dropping, e.g. a file promise (such as by opening a PNG in Preview, revealing the thumbnails sidebar, and then dragging the thumbnail onto the sample project’s window).

[…]

Since this bug causes semi-random memory corruption, it manifests in a large number of ways – not all of which are all that helpful.

[…]

SwiftUI’s onDrop(of:isTargeted:perform:) method makes no claims or promises as to what thread / queue it executes the closure on, and in fact according to the anonymous Apple engineer it never executes the closure on the main thread.

Now, while that may be the intent, the reality of that is wrong – in my experience it always executes the closure on the main thread (which makes a lot of sense to me as drag-and-drop event handling in AppKit has always been on the main thread in practice).

Apple also told him that NSPasteboard is not safe to use outside the main thread, even though that’s not documented, it’s not @MainActor, and Apple’s own code does do that.

  •  

EagleFiler 1.9.21

EagleFiler 1.9.21 is a maintenance release of my Mac digital filing cabinet and e-mail archiving app. It can now capture the selected messages from MailMaven, including all their metadata, and can link back to the original message. The capture key now works with the Helium browser, and importing from Mariner Paperless and Microsoft Outlook is improved as well.

  • There was an interesting regression caused by the fact that macOS now implements pop-up menus using separate windows (NSPopupMenuWindow) that post their own notifications for becoming key and for resigning key status.

  • Encrypted libraries need to be converted to APFS, since a future version of macOS will drop support for CoreStorage. You can do this now, or it’s possible that we’ll be able to offer an automatic converter in a future version.

  • There were more problems with PyObjC importing symbols, this time generic Swift classes that have angle brackets in their names. I had previously added more precise imports to skip over these symbols, which aren’t needed anyway, so it’s a mystery why a few users were still seeing this problem despite using the same macOS versions as everyone else. In any case, I adjusted the PyObjC importer to hopefully avoid problems with all such symbols, even if Apple adds more in future versions.

  • macOS Tahoe introduced a bug displaying custom folder icons, which was finally fixed in macOS 26.4.1.

Previously:

  •  

AppKit in macOS 27

macOS Golden Gate 27 Beta Release Notes:

AppKit adds NSRefreshController, providing pull-to-refresh functionality for NSScrollView.

[…]

NSToolbarItemGroup adds the role property and the NSToolbarItemGroupRole enum, allowing toolbar item groups to be tagged with a semantic role. NSSegmentedControl similarly adds a role property and the NSSegmentedControlRole enum, including a tabs role for controls that represent tab-based navigation and content selection.

[…]

NSTextSelectionManager provides common text selection interactions (click, drag, shift-click, double/triple-click word/line/paragraph selection) to a NSView with a set of NSGestureRecognizers rather than overriding NSEvent mouse methods. NSTextView now uses NSTextSelectionManager and provides its own set of NSGestureRecognizers to provide additional features in addition to text selection.

[…]

By default, NSMenu hides all menu item symbol images — non-symbol images remain visible. […] Use the new preferredImageVisibility property on NSMenuItem to customize the image visibility for your menu items. As in macOS 26.0, NSMenu automatically provides default visible menu item images for certain common system-wide menu items, such as Settings, Share, and Print.

AppKit updates:

Create events similar to UIControl events on NSControl with the new NSControl.Events type.

[…]

Initiate a drag operation from a gesture recognizer using the new beginDraggingSession(items:gesture:source:) method on NSView.

[…]

Update views automatically in response to Observable model changes using the guidance in Updating views automatically with observation tracking.

How is this different from what was announced last year?

Modernize your AppKit app:

Bring your AppKit app up to date with modern macOS conventions. Dive into handling input with control events and gesture recognizers, moving beyond traditional tracking loops. Enhance keyboard navigation in your app, implement graceful state restoration after restarts, and take advantage of new corner concentricity APIs that let your interface blend seamlessly with the macOS aesthetic.

Steve Troughton-Smith:

To summarize the singular AppKit session this year: hey remember all these APIs and design patterns from UIKit? Well they’re now in AppKit and you should use them! Also make your glass use interactive bounce effects.

Why? No reason!😉

TN3212:

In macOS 27, AppKit continues to standardize on gesture recognizers as the primary mechanism for input handling. This change directly affects Sidecar because gesture recognizers are the only way to respond to touch input from a Sidecar-connected iPad running iPadOS 27. If your app relies on tracking loops for mouse event handling, migrate to gesture recognizers to support Sidecar touch input.

This article explains how the gesture recognizer model works, how to implement gesture recognizers correctly for Sidecar touch input, how to update your existing event-handling code, and which APIs macOS 27 adds. Codebases that implement nextEvent(matching:) or mouseDown(with:), mouseDragged(with:), and mouseUp(with:) events are most affected by the updates discussed.

Greg Pierce:

After the AppKit session blindsided me a bit after telling me not to override mouseDown, and then telling me I should override hitTest

Mario Guzmán:

A few years ago, Apple introduced:

func tableView(_ tableView: NSTableView, userCanChangeVisibilityOf column: NSTableColumn) -> Bool

for NSTableView, which Is a native way users could control-click on a TableView column to show/hide columns.

This year, in #macOS27, they updated it to have a new “Reset to Defaults” option.

This is awesome bc I have done my own implementation of this feature JUST to have the option to “reset all columns” and now Apple just includes it!

Elevate your app’s text experience with TextKit:

Discover how to combine the convenience of built-in text views with the control of TextKit. We’ll show you how new APIs make it easy to extend UITextView and NSTextView with custom behaviors like line numbers and collapsible sections. We’ll also explore the TextKit architecture and walk through new caching and reuse policies for text attachments.

Previously:

  •  

UIKit in iOS 27

iOS & iPadOS 27 Beta Release Notes:

[You] can use UIScene.extendStateRestoration and UIScene.completeStateRestoration to extend state restoration for UIScene.ActivationState.background to UIScene.ActivationState.foreground lifecycle transitions.

[…]

iOS and iPadOS apps built with the 27.0 SDK or later are required to include a launch screen.

[…]

Siri can load resources from drag interactions installed in your app’s interface.

[…]

In apps built with the iOS 27.0 SDK, a presented view controller inherits its trait collection by walking up its view’s superview chain through the intermediate views of the presentation, rather than jumping directly to the presentation controller.

UIKit updates:

Use UICollectionViewCompositionalLayoutSectionProvider closures as part of automatic observation tracking to automatically invalidate and update compositional layouts when observable objects change.

[…]

Use UIRefreshControl and UIStepper in Mac apps built with Mac Catalyst. These controls are now fully supported in the Mac idiom.

[…]

Starting in iOS 27, apps built with the latest SDK must use the scene-based life cycle or they fail to launch.

[…]

Use NSTextTable, NSTextBlock, and NSTextTableBlock to represent table structures in attributed strings.

Modernize your UIKit app:

Discover the latest updates to UIKit. Learn how to update your iPhone app layouts to work great when resized with iPhone Mirroring and on iPad. Explore new APIs for tab and navigation bars, find out how to prepare your app for new Apple Intelligence capabilities, and get introduced to a skill for your coding agent of choice that helps modernize your codebase.

Kyle Howells:

iOS 27’s UIKit is a tiny release in terms of API changes, but does have some changes. There are no new top-level paradigms, but there’s an new addition to TextKit 2, a new scene accessory API, Liquid-Glass-era bar minimization controls, and a small amount of quality-of-life additions to menus, tab bars, and drag interactions.

Hartley Charlton:

Apple appears to be laying the groundwork for a foldable iPhone in iOS 27, with new references discovered in the operating system’s frameworks and a notable emphasis on flexible app layouts at this year’s Platforms State of the Union.

Jordan Morgan:

The nav bar and its friends got quite a bit of attention, and to be honest that’s where we will find most of the changes. They adapt to all sorts of sizes and situations…hmmm, I WONDER WHY!?

[…]

A few years ago, I wondered if UIKit would be deprecated altogether. That would’ve been drastic, sure, but I did wonder. These days, I don’t share the same concern anymore. SwiftUI gets better each year, and yeah — it’ll have top billing. But UIKit is solid, and it appears to be a core part of Apple’s strategy into the future.

Not much changed this year, and not much was added that’s flashy. But, that’s true of iOS 27 in several ways.

Previously:

  •  

Golden Gate Menu Icons

Wesley Hilliard:

macOS Tahoe threw an icon on every menu item, making them impossible to distinguish at a glance. macOS Golden Gate has rectified that design taboo with blessedly iconless menus.

Apple:

In macOS 27.0, menu bar and context menus present a reduced set of menu item images, similar to the behavior prior to macOS 26.0. By default, NSMenu hides all menu item symbol images — non-symbol images remain visible. For menu items created from a xib file, NSMenu also observes the value of the “macOS 26.0 only” checkbox in the menu item inspector. If this checkbox is unchecked, the menu item image remains visible; if checked, it is hidden. These changes in menu item image visibility apply to applications linked on macOS 26.0 and later. Review the updated Human Interface Guidelines to determine which menu items in your app should still display images. Use the new preferredImageVisibility property on NSMenuItem to customize the image visibility for your menu items. As in macOS 26.0, NSMenu automatically provides default visible menu item images for certain common system-wide menu items, such as Settings, Share, and Print.

Joachim Kurtz:

„Icons in menus are now hidden by default“ and you can specifically enable them to draw attention to the most important actions.

Don’t get me wrong, this is a great change! But to take a full year and your lead designer leaving to figure out that this was a mistake… woof…

Dominik Wagner:

I like that Menu Icons now are hidden by default again on macOS - Quite a lot of concessions towards liquid glass being the wrong move last year. Takes courage to take so many steps back, literally. I’m appreciating that. Even if they present it as improvements rather than “undo” - that’s just what one has to do for marketing.

Previously:

Update (2026-06-11): John Gruber (Mastodon, Hacker News, MacRumors):

Wonderful news in MacOS 27 Golden Gate: the icons are gone. It’s like Tahoe’s menu item icons never happened. Prokopov noted it on Mastodon with before and after screenshots, and mentions that Apple has updated the Human Interface Guidelines accordingly[…]

[…]

This is my favorite news from all of WWDC this week.

Marcin Wichary:

Kudos to Nielsen and Prokopov for pushing on this and explaining the problem so well. This wasn’t about ugly icons. This was about improper use and misunderstanding of iconography.

  •  
❌