Post

Replies

Boosts

Views

Activity

FileManager.contentsEqual(atPath:andPath:) very slow
Until now I was using FileManager.contentsEqual(atPath:andPath:) to compare file contents in my App Store app, but then a user reported that this operation is way slower than just copying the files (which I made faster a while ago, as explained in Making filecopy faster by changing block size). I thought that maybe the FileManager implementation reads the two files with a small block size, so I implemented a custom comparison with the same block size I use for filecopy (as explained in the linked post), and it runs much faster. When using the code for testing repeatedly also found on that other post, this new implementation is about the same speed as FileManager for 1KB files, but runs 10-20x faster for 1MB files or bigger. Feel free to comment on my implementation below. extension FileManager { func fastContentsEqual(atPath path1: String, andPath path2: String, progress: (_ delta: Int) -> Bool) -> Bool { do { let bufferSize = 16_777_216 let sourceDescriptor = open(path1, O_RDONLY | O_NOFOLLOW, 0) if sourceDescriptor < 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } let sourceFile = FileHandle(fileDescriptor: sourceDescriptor) let destinationDescriptor = open(path2, O_RDONLY | O_NOFOLLOW, 0) if destinationDescriptor < 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } let destinationFile = FileHandle(fileDescriptor: destinationDescriptor) var equal = true while autoreleasepool(invoking: { let sourceData = sourceFile.readData(ofLength: bufferSize) let destinationData = destinationFile.readData(ofLength: bufferSize) equal = sourceData == destinationData return sourceData.count > 0 && progress(sourceData.count) && equal }) { } if close(sourceDescriptor) < 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } if close(destinationDescriptor) < 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } return equal } catch { return contentsEqual(atPath: path1, andPath: path2) // use this as a fallback for unsupported files (like symbolic links) } } }
2
0
219
Jul ’25
NSTableView.reloadData(forRowIndexes:columnIndexes:) causes wrong subview layout when usesAutomaticRowHeights = true
I have a table view where each row has two labels, one left-aligned and one right-aligned. I would like to reload a single row, but doing so causes the right-aligned label to hug the left-aligned label. Before the reload: After the reload: Reloading the whole table view instead, or disabling automatic row height, solves the issue. Can a single row be reloaded without resorting to these two workarounds? I created FB13534100 1.5 years ago but got no response. class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate { override func loadView() { let tableView = NSTableView() tableView.translatesAutoresizingMaskIntoConstraints = false tableView.dataSource = self tableView.delegate = self tableView.usesAutomaticRowHeights = true let column = NSTableColumn() column.width = 400 tableView.addTableColumn(column) let scrollView = NSScrollView(frame: CGRect(x: 0, y: 0, width: 500, height: 500)) scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.documentView = tableView view = scrollView Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { _ in print("reload") tableView.reloadData(forRowIndexes: IndexSet(integer: 2), columnIndexes: IndexSet(integer: 0)) // tableView.reloadData() } } func numberOfRows(in tableView: NSTableView) -> Int { return 5 } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let cell = NSTableCellView() let textField1 = NSTextField(labelWithString: "hello") textField1.translatesAutoresizingMaskIntoConstraints = false let textField2 = NSTextField(wrappingLabelWithString: "world") textField2.translatesAutoresizingMaskIntoConstraints = false textField2.alignment = .right let stack = NSStackView(views: [ textField1, textField2 ]) stack.translatesAutoresizingMaskIntoConstraints = false stack.distribution = .fill cell.addSubview(stack) NSLayoutConstraint.activate([stack.topAnchor.constraint(equalTo: cell.topAnchor, constant: 0), stack.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 0), stack.bottomAnchor.constraint(equalTo: cell.bottomAnchor, constant: 0), stack.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: 0)]) return cell } }
Topic: UI Frameworks SubTopic: AppKit Tags:
2
0
131
Aug ’25
Window title bar in macOS 26 is drawn even if titlebarAppearsTransparent = true
macOS 26 sometimes draws the title bar background even when setting NSWindow.titlebarAppearsTransparent = true and I don't understand the logic behind it, or how I can turn this off. I'm trying to do something similar to Xcode's "Welcome to Xcode" window which has a left view and a right table view. In my simplified example, the window contains a label and a text view. This used to work in macOS 15, but in macOS 26 the text view is partially covered by the title bar: As soon as I remove the line scrollView.hasVerticalScroller = true, the title bar isn't drawn anymore: The title bar also isn't drawn when removing the view on the left of the text view: I created FB20341654. This may be related to this other issue: NSWindow.titlebarAppearsTransparent only works after collapsing and expanding sidebar @main class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { let window = NSWindow(contentViewController: ViewController()) window.titlebarAppearsTransparent = true window.titleVisibility = .hidden window.styleMask = [.titled, .closable, .fullSizeContentView] window.makeKeyAndOrderFront(nil) } } class ViewController: NSViewController { override func loadView() { view = NSView(frame: CGRect(x: 0, y: 0, width: 400, height: 200)) let scrollView = NSScrollView() scrollView.hasVerticalScroller = true // commenting this line out solves the issue scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.automaticallyAdjustsContentInsets = false let documentView = NSTextView() documentView.string = (0..<10).map({ "\($0)" }).joined(separator: "\n") scrollView.documentView = documentView let stack = NSStackView(views: [ NSTextField(labelWithString: "asdfasdfasdfasdf"), // commenting this line out also solves the issue scrollView ]) stack.orientation = .horizontal view.addSubview(stack) NSLayoutConstraint.activate([stack.topAnchor.constraint(equalTo: view.topAnchor), stack.leadingAnchor.constraint(equalTo: view.leadingAnchor), stack.trailingAnchor.constraint(equalTo: view.trailingAnchor), stack.bottomAnchor.constraint(equalTo: view.bottomAnchor)]) } }
Topic: UI Frameworks SubTopic: AppKit Tags:
2
0
249
Sep ’25
URL.startAccessingSecurityScopedResource() returns false for "On My iPad" after a while
My app allows to save user-selected URLs in a list and browse them with a tap. A user reported that the app often shows that when browsing their saved entry for "On My iPad", it's apparently empty (it contains no files). I saved "On My iPad" in my own list some time ago and noticed that the same issue occurs. The URL seems to be correctly resolved from the saved bookmark data, but I noticed that url.startAccessingSecurityScopedResource() returns false. The other URL I saved some time ago is iCloud Drive, which I can access without issues. If I select "On My iPad" again in a file importer, create new bookmark data from it and resolve the URL from it, access works correctly. I create bookmark data like this: let data = try url.bookmarkData(includingResourceValuesForKeys: [.localizedNameKey, .pathKey, .volumeIsLocalKey]) and resolve URLs like this: let url = try URL(resolvingBookmarkData: data, bookmarkDataIsStale: &bookmarkDataIsStale) bookmarkDataIsStale is false for both the working and not working URLs for "On My iPad". The two bookmark data are different though, even if url.path is the same. What could be the issue?
2
0
162
4w
UIMainMenuSystem: remove "Paste and Match Style" item from Edit menu
The default app menu on iPadOS 26 includes an Edit menu with items (among others) Cut, Copy, Paste, Paste and Match Style. I want to remove the last one. I tried the following but nothing worked: let configuration = UIMainMenuSystem.Configuration() configuration.textFormattingPreference = .removed UIMainMenuSystem.shared.setBuildConfiguration(configuration) { builder in builder.remove(action: .pasteAndMatchStyle) if let command = builder.menu(for: .edit)?.children.first(where: { ($0 as? UICommand)?.action == #selector(UIResponderStandardEditActions.pasteAndMatchStyle(_:)) }) as? UICommand { command.attributes.insert(.hidden) } }
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
144
3w
NSMenu.popUp(positioning:at:in:) doesn't enable menu items when opened inside modal window
In my app I use NSMenu.popUp(positioning:at:in:) for displaying a menu in response to the user clicking a button. But it seems that when the menu is opened inside a modal window, all the menu items are always disabled. Using NSMenu.popUpContextMenu(_:with:for:) instead works. What's the reason and what's the difference between the two methods? According to the documentation, one is for opening "popup menus" and the other for opening "context menus", but I cannot see an explanation of the difference between the two. @main class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { let window = NSWindow(contentViewController: ViewController()) NSApp.runModal(for: window) } } class ViewController: NSViewController { override func loadView() { let button = NSButton(title: "Click", target: self, action: #selector(click(_:))) view = NSView(frame: CGRect(x: 0, y: 0, width: 400, height: 400)) view.addSubview(button) } @objc func click(_ sender: Any?) { let menu = NSMenu(title: "") menu.addItem(withTitle: "asdf", action: #selector(asdf(_:)), keyEquivalent: "") menu.addItem(withTitle: "bla", action: nil, keyEquivalent: "") menu.items[0].target = self menu.items[1].target = self // NSMenu.popUpContextMenu(menu, with: NSApp.currentEvent!, for: view) // this works menu.popUp(positioning: nil, at: .zero, in: view) // this doesn't work } @IBAction func asdf(_ sender: Any) { print(0) } }
Topic: UI Frameworks SubTopic: AppKit Tags:
3
0
850
Feb ’24
Select directory in SwiftUI file importer
I want to show a file importer that allows to select both regular files as well as directories. When running the following code on iOS, I can tap a PDF file and the file importer closes as expected, but when tapping a directory, the file importer shows its contents. How can I instead select that directory and close the file importer? The navigation bar shows a Cancel button, but no Open button. struct FileView: View { @State private var showFileImporter = false var body: some View { ScrollView { VStack(alignment: .leading) { VStack(alignment: .center) { Button("Open") { showFileImporter = true } } } } .fileImporter(isPresented: $showFileImporter, allowedContentTypes: [.pdf, .directory], onCompletion: { result in // TODO }) } }
3
0
2.6k
Apr ’24
Apple Care tells users who cannot download/update app from App Store that the third-party developer is responsible
While this isn't an issue directly related with programming, I would like to share my frustration with Apple Care and their knowledge of how App Store and third-party apps work. Perhaps someone at Apple can do something about it. Every now and then a user of one of my apps contacts me asking why they get an error when downloading or updating the app in the App Store ("Unable to Download App. “App” could not be installed. Please try again later."). I tell them that third-party developers have no power over the App Store or its download/update process, and this is an issue they have to solve with Apple Care. But when they contact Apple Care, they are told that since it's an issue with a third-party app, they have to contact the app developer. Sometimes the user is more inclined to believe what Apple Care tells them and they get angry at me. In any case, I feel helpless and frustrated, because I would love to help them, but have no means of doing so. There is something about the concept of App Store that makes some users believe that third-party developers have more power than they actually have: sometimes, for example, users contact me directly, or even leave reviews on the App Store, asking for a refund, which of course only Apple can do. Have you had a similar experience? Can some engineer at Apple instruct Apple Care that third-party developers cannot help with App Store download/update issues, so that App Store users don't get mad at the app developers for not being able to install/update their app?
3
0
821
Apr ’24
NSProgressIndicator bindings don't do anything
I'm trying to bind a NSProgressIndicator to Progress, but with the following code I only get an indeterminate progress indicator with a blue bar forever bouncing left and right, even after the two timers fire. According to the documentation: Progress is indeterminate when the value of the totalUnitCount or completedUnitCount is less than zero or if both values are zero. What am I doing wrong? class ViewController: NSViewController { let progress = Progress() override func loadView() { view = NSView(frame: CGRect(x: 0, y: 0, width: 500, height: 500)) let progressIndicator = NSProgressIndicator(frame: CGRect(x: 100, y: 100, width: 100, height: 100)) progressIndicator.bind(.isIndeterminate, to: progress, withKeyPath: "isIndeterminate") progressIndicator.bind(.value, to: progress, withKeyPath: "completedUnitCount") progressIndicator.bind(.maxValue, to: progress, withKeyPath: "totalUnitCount") progressIndicator.startAnimation(nil) view.addSubview(progressIndicator) progress.completedUnitCount = 3 progress.totalUnitCount = 10 Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in print(1) self.progress.completedUnitCount = 6 } Timer.scheduledTimer(withTimeInterval: 6, repeats: false) { _ in print(2) self.progress.completedUnitCount = 0 self.progress.totalUnitCount = 0 } } }
Topic: UI Frameworks SubTopic: AppKit Tags:
3
0
899
Jun ’24
Share settings from SwiftUI in-app settings view to other views
In SwiftUI we can use @AppStorage to save app settings. In my app, I have a settings view which allows the user to change various settings. Since there are many of them, it's not practical to declare a binding for each setting between the settings view and whatever other views effectively use that setting. Is there a more convenient way to store a setting in one view and access it in another view?
3
0
929
Jun ’24
Sample projects of NEFilterProvider use IPC but the documentation says that it blocks IPC
The sample project Filtering Network Traffic uses IPC (NSXPCConnection etc.) to send data from the network extension to the app, but the documentation for NEFilterProvider says The sandbox prevents the Filter Data Provider extension from moving network content outside of its address space by blocking all network access, IPC, and disk write operations. Since my network extension forwards all network traffic to the app so that the user can see it, I was wondering when the app isn’t running and the user shuts down the machine, if the network extension could write the flows it wasn’t able to forward to the app to disk, so that it could read them on the next successful connection to the app. Then almost by accident I read again the documentation and according to the quoted passage a network extension cannot write to disk, but it also cannot use IPC. Is NSXPCConnection not considered IPC, or could the statement that it cannot write to disk be false as well?
3
0
520
Jul ’24
How to debug Quick Look Preview Extension
When I launch the Quick Look Preview Extension target in Xcode, an app called Quick Look Simulator opens with an almost empty window: Online I read that the Terminal command qlmanage allows to test Quick Look plugins (which I think were an older format for creating Quick Look extensions), but running qlmanage -p /path/to/previewed/file -c public.text -g /path/to/QuickLookPreviewExtension.appex (where QuickLookPreviewExtension.appex is generated by the Xcode build and is located in the DerivedData folder) gives an error Can't get generator at QuickLookPreviewExtension.appex How can I debug a Quick Look Preview Extension?
3
2
991
May ’25
How can I share a developer-signed app through my website?
In the past, I used to export a developer-signed test version of my macOS app in Xcode, create a zip archive from the Finder, upload it to my website and share the link to the testers. The last time I did this with macOS 14 the tester was still able to download the test app and run it. But it seems that with macOS 15 the trick to open the context menu on the downloaded app and click Open to bypass the macOS warning that the app couldn't be checked when simply double-clicking it, doesn't work anymore. Now I'm always shown an alert that macOS couldn't check the app for malware, and pushes me to move it to the bin. In this StackOverflow topic from 10 years ago they suggested to use ditto and tar to compress and uncompress the app, but neither worked for me. How can I share macOS apps that I signed myself with testers without physically handing them a drive containing the uncompressed app?
3
0
812
Nov ’24