A customer of mine reported that since updating to macOS 15 they aren't able to use my app anymore, which performs a deep scan of selected folders by recursively calling getattrlistbulk. The problem is that the app apparently keeps scanning forever, with the number of scanned files linearly increasing to infinity.
This happens for some folders on a SMB volume.
The customer confirmed that they can reproduce the issue with a small sample app that I attach below. At first, I created a sample app that only scans the contents of the selected folder without recursively scanning the subcontents, but the issue didn't happen anymore, so it seems to be related to recursively calling getattrlistbulk.
The output of the sample app on the customer's Mac is similar to this:
start scan /Volumes/shares/Backup/Documents level 0 fileManagerCount 2847
continue scan /Volumes/shares/Backup/Documents new items 8, sum 8, errno 34
/Volumes/shares/Backup/Documents/A.doc
/Volumes/shares/Backup/Documents/B.doc
...
continue scan /Volumes/shares/Backup/Documents new items 7, sum 1903, errno 0
/Volumes/shares/Backup/Documents/FKV.pdf
/Volumes/shares/Backup/Documents/KFW.doc
/Volumes/shares/Backup/Documents/A.doc
/Volumes/shares/Backup/Documents/B.doc
...
which shows that counting the number of files in the root folder by using
try FileManager.default.contentsOfDirectory(atPath: path).count
returns 2847, while getattrlistbulk lists about 1903 files and then starts listing the files from the beginning, not even between repeated calls, but within a single call.
What could this issue be caused by?
(The website won't let me attach .swift files, so I include the source code of the sample app as a text attachment.)
ViewController.swift
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I used to be able to see how many TSIs are still available for the membership year on the developer website, but now I cannot find it anymore.
Is it still 2 per year, or has it been recently changed to unlimited per year?
All the threads only contain system calls. The crashed thread only contains a single call to my app's code which is main.swift:12.
What could cause such a crash?
crash.txt
Before updating to macOS 15 Sequoia, I used to be able to create file bookmarks with this code:
let openPanel = NSOpenPanel()
openPanel.runModal()
let url = openPanel.urls[0]
do {
let _ = try url.bookmarkData(options: [.withSecurityScope])
} catch {
print(error)
}
Now I get an error
Error Domain=NSCocoaErrorDomain Code=256 "Failed to retrieve app-scope key"
These are the entitlements:
com.apple.security.app-sandbox
com.apple.security.files.user-selected.read-write
com.apple.security.files.bookmarks.app-scope
Strangely, my own apps continued working, after updating to macOS 15 some days ago, until a few moments ago. Then it seems that all of a sudden my existing bookmarks couldn't be resolved anymore, and no new bookmarks could be created. What could be the problem?
The following code works when compiling for macOS:
print(NSMutableDictionary().isEqual(to: NSMutableDictionary()))
but produces a compiler error when compiling for iOS:
'NSMutableDictionary' is not convertible to '[AnyHashable : Any]'
NSDictionary.isEqual(to:) has the same signature on macOS and iOS. Why does this happen? Can I use NSDictionary.isEqual(_:) instead?
I rarely use the Shortcuts app, so it took me a while to notice that my app's app intents all show incorrectly on macOS 15. On macOS 14 and 13, they used to show correctly, but now it seems that all localized strings show the key rather than the localized value.
@available(iOS 16.0, macOS 13.0, *)
struct MyAppIntent: AppIntent {
static let title = LocalizedStringResource("key1", comment: "")
static let description = IntentDescription(LocalizedStringResource("key2", comment: ""))
...
}
In Localizable.xcstrings file I have defined all the strings, for instance I have associated key1 with the value Title, but while the Shortcuts app used to display Title, it now displays key1.
Is this a known issue or did something change in macOS 15 that would require me to update something?
I have a very basic App Intent extension in my macOS app that does nothing than accepting two parameters, but running it in Shortcuts always produces the error "The action “Compare” could not run because an internal error occurred.".
What am I doing wrong?
struct CompareIntent: AppIntent {
static let title = LocalizedStringResource("intent.compare.title")
static let description = IntentDescription("intent.compare.description")
static let openAppWhenRun = true
@Parameter(title: "intent.compare.parameter.original")
var original: String
@Parameter(title: "intent.compare.parameter.modified")
var modified: String
func perform() async throws -> some IntentResult {
return .result()
}
}
Some time ago I read somewhere that one can get a file icon on iOS like this:
UIDocumentInteractionController(url: url).icons.last!)
but this always returns the following image for every file:
Today I tried the following, which always returns nil:
(try? url.resourceValues(forKeys: [.effectiveIconKey]))?.allValues[.effectiveIconKey] as? UIImage
Is there any way to get a file icon on iOS?
You can try the above methods in this sample app:
struct ContentView: View {
@State private var isPresentingFilePicker = false
@State private var url: URL?
var body: some View {
VStack {
Button("Open") {
isPresentingFilePicker = true
}
if let url = url {
Image(uiImage: UIDocumentInteractionController(url: url).icons.last!)
if let image = (try? url.resourceValues(forKeys: [.effectiveIconKey]))?.allValues[.effectiveIconKey] as? UIImage {
Image(uiImage: image)
} else {
Text("none")
}
}
}
.padding()
.fileImporter(isPresented: $isPresentingFilePicker, allowedContentTypes: [.data]) { result in
do {
let url = try result.get()
if url.startAccessingSecurityScopedResource() {
self.url = url
}
} catch {
preconditionFailure(error.localizedDescription)
}
}
}
}
On macOS, we have didMountNotification but there doesn't seem to be an equivalent for iOS. Is there a way to be notified when a volume is mounted on iOS? I would like to use it in my iOS app I'm currently porting from macOS, which starts a synchronization from the volume (which has been previously selected in a NSOpenPanel) as soon as it's mounted.
On macOS, the Finder allows to connect to a server and store the login credentials. When creating a bookmark to a file on a server and resolving it again, the server is mounted automatically (unless I provide the option URL.BookmarkResolutionOptions.withoutMounting).
I just tried connecting to my Mac from my iPad via SMB in the Files app and storing a bookmark to a file on the server, but disconnecting the server and trying to resolve the bookmark throws the error (I translated the English text from Italian):
Error Domain=NSFileProviderErrorDomain Code=-2001 "No file provider was found with the identifier "com.apple.SMBClientProvider.FileProvider"'" UserInfo={NSLocalizedDescription=No file provider was found with the identifier "com.apple.SMBClientProvider.FileProvider"., NSUnderlyingError=0x302a1a340 {Error Domain=NSFileProviderErrorDomain Code=-2013 "(null) "}}
Every time I disconnect and reconnect to the server, selecting the same file returns a different path. The first time I got
/private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/WtFD3Ausername/path/to/file.txt
The next time WtFD3A changed to EqHc2g and so on.
Is it not possible to automatically mount a server when resolving a bookmark on iOS?
The following code allows to reproduce the issue:
struct ContentView: View {
@State private var isPresentingFilePicker = false
@AppStorage("bookmarkData") private var bookmarkData: Data?
@State private var url: URL?
@State private var stale = false
@State private var error: Error?
var body: some View {
VStack {
Button("Open") {
isPresentingFilePicker = true
}
if let url = url {
Text(url.path)
} else if bookmarkData != nil {
Text("couldn't resolve bookmark data")
} else {
Text("no bookmark data")
}
if stale {
Text("bookmark is stale")
}
if let error = error {
Text("\(error)")
.foregroundStyle(.red)
}
}
.padding()
.fileImporter(isPresented: $isPresentingFilePicker, allowedContentTypes: [.data]) { result in
do {
let url = try result.get()
if url.startAccessingSecurityScopedResource() {
bookmarkData = try url.bookmarkData()
}
} catch {
self.error = error
}
}
.onChange(of: bookmarkData, initial: true) { _, bookmarkData in
if let bookmarkData = bookmarkData {
do {
url = try URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &stale)
} catch {
self.error = error
}
}
}
}
}
This crash report for one of my apps was downloaded by Xcode. Apparently the app crashed while releasing an object of type Scan.File, which is a Swift class held in an array in the Scan.Directory class. I'm not doing any manual reference counting or low-level stuff with that object.
What could cause such a crash?
crash.crash
I was just comparing the build settings of two of my apps to try to understand why they behave differently (one of them uses the full screen on iPad, and the other one has small top and bottom black borders, although that's not the issue I want to discuss now). I saw that the option CLANG_CXX_LANGUAGE_STANDARD is set to gnu++0x for the older project, while it's set to gnu++17 for the newer one. The documentation lists different possible values and also a default one:
Compiler Default: Tells the compiler to use its default C++ language dialect. This is normally the best choice unless you have specific needs. (Currently equivalent to GNU++98.)
If it really is the best choice (normally), why is it not used when creating a new default Xcode project? Or is it better to select a newer compiler version (GNU++98 sounds quite old compared to GNU++17)? Also, does this affect Swift code?
For some time now Xcode has been downloading crash reports from users of my app about crashes related to arrays. One of them looks like this:
...
Code Type: ARM-64
Parent Process: launchd [1]
User ID: 501
Date/Time: 2024-07-18 14:59:40.4375 +0800
OS Version: macOS 15.0 (24A5289h)
...
Crashed Thread: 0
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000001045048b8
Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5
Terminating Process: exc handler [1771]
Thread 0 Crashed:
0 MyApp 0x00000001045048b8 specialized Collection.map<A>(_:) + 596
1 MyApp 0x00000001045011e4 MyViewController.validateToolbarButtons() + 648 (MyViewController.swift:742)
...
The relevant code looks like this:
class MyViewController {
func validateToolbarButtons() {
let indexes = tableView.clickedRow == -1 || tableView.selectedRowIndexes.contains(tableView.clickedRow) ? tableView.selectedRowIndexes : IndexSet(integer: tableView.clickedRow)
let items = indexes.map({ myArray[$0] })
...
}
}
The second crash looks like this:
...
Code Type: X86-64 (Native)
Parent Process: launchd [1]
User ID: 502
Date/Time: 2024-07-15 15:53:35.2229 -0400
OS Version: macOS 15.0 (24A5289h)
...
Crashed Thread: 0
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4
Terminating Process: exc handler [13244]
Thread 0 Crashed:
0 libswiftCore.dylib 0x00007ff812904fc0 _assertionFailure(_:_:flags:) + 288
1 MyApp 0x0000000101a31e04 specialized _ArrayBuffer._getElementSlowPath(_:) + 516
2 MyApp 0x00000001019d04eb MyObject.myProperty.setter + 203 (MyObject.swift:706)
3 MyApp 0x000000010192f66e MyViewController.controlTextDidChange(_:) + 190 (MyViewController.swift:166)
...
And the relevant code looks like this:
class MyObject {
var myProperty: [MyObject] {
get {
...
}
set {
let items = newValue.map({ $0.id })
...
}
}
}
What could cause such crashes? Could they be caused by anything other than concurrent access from multiple threads (which I'm quite sure is not the case here, as I only access these arrays from the main thread)?
I was just having a look at some crash reports downloaded by Xcode, and I noticed the same wrong pattern I already mentioned here: the crash reports indicate that method A calls method B, which is impossible.
In the first crash report below, method MainViewController.showSettings seems to be called by ConfirmMoveViewController.openSourceInFinder, which is impossible. ConfirmMoveViewController.openSourceInFinder is a context menu action in a modal window, and MainViewController.showSettings is in a completely different window and the two methods have no relation whatsoever.
In the second crash report below, MainViewController.setSortMode is triggered by the press of a button (and nothing else) but seems to be called by OtherViewController.copy that can be triggered by a context menu (or keyboard shortcut). The two methods have no relation whatsoever. The rest of the stack trace confirm that it's indeed the button that was pressed.
This seems to me like a quite serious bug in how macOS creates crash reports.
1.crash
2.crash
When creating a default macOS document-based Xcode project and using the code below (and wiring the File menu's Print item to printDocument: instead of the default print:, which does nothing), opening the print panel causes PrintView.knowsPageRange(_:) to be called twice.
Is this a bug? My app populates PrintView dynamically, and for large documents it can be quite inefficient to populate it once, only for the contents to be immediately discarded and populated again.
A workaround that came to my mind would be to check if the print options have changed, though I'm not sure if it's a reliable indicator that the print preview is effectively the same.
I created FB17018494.
class Document: NSDocument {
override func makeWindowControllers() {
addWindowController(NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil).instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! NSWindowController)
}
override func printOperation(withSettings printSettings: [NSPrintInfo.AttributeKey : Any]) throws -> NSPrintOperation {
return NSPrintOperation(view: PrintView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)), printInfo: NSPrintInfo(dictionary: printSettings))
}
}
class PrintView: NSView {
override func knowsPageRange(_ range: NSRangePointer) -> Bool {
print("knowsPageRange")
range.pointee = NSRange(location: 1, length: 1)
return true
}
}
Topic:
UI Frameworks
SubTopic:
AppKit