Post

Replies

Boosts

Views

Activity

NSTableView is unresponsive when inside a modal window shown in DispatchQueue.main.async
In my app I have a background task performed on a custom DispatchQueue. When it has completed, I update the UI in DispatchQueue.main.async. In a particular case, the app then needs to show a modal window that contains a table view, but I have noticed that when scrolling through the tableview, it only responds very slowly. It appears that this happens when the table view in the modal window is presented in DispatchQueue.main.async. Presenting it in perform(_:with:afterDelay:) or in a Timer.scheduledTimer(withTimeInterval:repeats:block:) on the other hand works. Why? This seems like an ugly workaround. I created FB7448414 in November 2019 but got no response. @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { let windowController = NSWindowController(window: NSWindow(contentViewController: ViewController())) // 1. works // runModal(for: windowController) // 2. works // perform(#selector(runModal), with: windowController, afterDelay: 0) // 3. works // Timer.scheduledTimer(withTimeInterval: 0, repeats: false) { [self] _ in // self.runModal(for: windowController) // } // 4. doesn't work DispatchQueue.main.async { self.runModal(for: windowController) } } @objc func runModal(for windowController: NSWindowController) { NSApp.runModal(for: windowController.window!) } } class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate { override func loadView() { let tableView = NSTableView() tableView.dataSource = self tableView.delegate = self tableView.addTableColumn(NSTableColumn()) let scrollView = NSScrollView(frame: CGRect(x: 0, y: 0, width: 400, height: 400)) scrollView.documentView = tableView scrollView.hasVerticalScroller = true scrollView.translatesAutoresizingMaskIntoConstraints = false view = scrollView } func numberOfRows(in tableView: NSTableView) -> Int { return 100 } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let view = NSTableCellView() let textField = NSTextField(labelWithString: "\(row)") textField.translatesAutoresizingMaskIntoConstraints = false view.addSubview(textField) NSLayoutConstraint.activate([textField.leadingAnchor.constraint(equalTo: view.leadingAnchor), textField.trailingAnchor.constraint(equalTo: view.trailingAnchor), textField.topAnchor.constraint(equalTo: view.topAnchor), textField.bottomAnchor.constraint(equalTo: view.bottomAnchor)]) return view } }
4
0
183
Jun ’25
Selecting ~/Library in open panel doesn't give access to ~/Library/Mail
A user of my app brought to my attention that unless they select their ~/Library/Mail folder explicitly in an open panel, they get an error when scanning it inside my app. I can confirm that I also get a permission error when trying to scan it as a subfolder of ~/Library, but not if I select it directly. I'm assuming this is intentional, but it would be nice to have an explanation or some documentation that I can point my users to when they encounter what appears to them as a bug in my app. What makes this matter even more confusing is that selecting a folder in any open panel of an app gives the app access to it for the lifetime of the app, but after restarting the app, access is lost again (unless it has a bookmark to it). This was probably the reason why the user thought that it worked in another app but not in mine. This is the code I use to scan: let openPanel = NSOpenPanel() openPanel.canChooseDirectories = true if openPanel.runModal() == .cancel { return } let enumerator = FileManager.default.enumerator(at: openPanel.urls[0], includingPropertiesForKeys: nil) { url, error in print(url.path, error) return true } while let url = enumerator?.nextObject() as? URL { } And this the error related to the Mail folder: ~/Library/Mail Error Domain=NSCocoaErrorDomain Code=257 "The file “Mail” couldn’t be opened because you don’t have permission to view it." UserInfo={NSURL=file:///~/Library/Mail, NSFilePath=/~/Library/Mail, NSUnderlyingError=0x600002991470 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
4
0
126
Sep ’25
SpriteKit scene used as SCNView.overlaySKScene crashes due to SKShapeNode
I recently published my first game on the App Store. It uses SceneKit with a SpriteKit overlay. All crashes Xcode downloaded for it so far are related to some SpriteKit/SceneKit internals. The most common crash is caused by SKCShapeNode::_NEW_copyRenderPathData. What could cause such a crash? crash.crash While developing this game (and the BoardGameKit framework that appears in the crash log) over the years I experienced many crashes presumably caused by the SpriteKit overlay (I opened a post SceneKit app randomly crashes with EXC_BAD_ACCESS in jet_context::set_fragment_texture about such a crash in September 2024), and other people on the internet also mention that they experience crashes when using SpriteKit as a SceneKit overlay. Should I use a separate SKView and lay it on top of SCNView rather than setting SCNView.overlaySKScene? That seemed to solve the crashes for a guy on stackoverflow, but is it also encouraged by Apple? I know SceneKit is deprecated, but according to Apple critical bugs would still be fixed. Could this be considered a critical bug?
4
0
624
2w
NEFilterDataProvider.handleNewFlow(_:) gets called with same flow ids multiple times
Since NEFilterFlow.identifier is documented as The unique identifier of the flow., I thought I could use it to store the flow by its identifier in a dictionary in order to retrieve it later. I do this when the system extension pauses a flow because it needs to ask the user whether the flow should eventually be allowed or dropped. But then I noticed that sometimes when allowing a previously paused flow, identified by its identifier, my system extension doesn't find that flow anymore. After some debugging it turned out that this happens because I stored at least one other flow with the same id which, when confirmed, is removed again from the dictionary, so there is no more flow with that identifier waiting in the dictionary. Is it expected that the identifiers are recycled for different flows, or does it mean that the same flow is effectively being passed to handleNewFlow(_:) multiple times, such as if the extension waited "too long" between pausing a flow and allowing or dropping it? handle(_:) can be called multiple times for the same flow, but why .handleNewFlow(_:)? All flows with duplicate ids seem to be UDP, and the local host and port and remote host and port are the same for all flows with the same id. Most of the duplicate flows have a process path of /usr/sbin/mDNSResponder (resolved with the sourceAppAuditToken).
5
0
703
Dec ’23
NSAttributedString.enumerateAttribute(_:in) crashes with custom attribute in macOS Sequoia
The following code crashes on macOS 15 Sequoia: import Foundation let key = NSAttributedString.Key("org.example.key") let value = Value() let string = NSMutableAttributedString() string.append(NSAttributedString(string: "a", attributes: [:])) string.append(NSAttributedString(string: "b", attributes: [key: value])) string.append(NSAttributedString(string: "c", attributes: [:])) string.enumerateAttribute(key, in: NSRange(location: 0, length: string.length)) { value, range, stop in print(range) } class Value: Equatable, Hashable { static func == (lhs: Value, rhs: Value) -> Bool { return lhs === rhs } func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } } The error is EXC_BAD_ACCESS (code=1, address=0x0) I wanted to run it on my external macOS 14 partition to confirm that it didn't crash before updating to macOS 15, but for some reason macOS will just restart and boot again into macOS 15. So I tried with macOS 13, which I was allowed to start for some reason, and I was able to confirm that the code doesn't crash. Is this a known issue, and is there a workaround? Removing the two lines that add the letters a and c, or just declaring class Value without conformance to Equatable, Hashable, interestingly, solves the issue.
5
0
676
Oct ’24
Take correctly sized screenshots with ScreenCaptureKit
I've been using CGWindowListCreateImage which automatically creates an image with the size of the captured window. But SCScreenshotManager.captureImage(contentFilter:configuration:) always creates images with the width and height specified in the provided SCStreamConfiguration. I could be setting the size explicitly by reading SCWindow.frame or SCContentFilter.contentRect and multiplying the width and height by SCContentFilter.pointPixelScale , but it won't work if I want to keep the window shadow with SCStreamConfiguration.ignoreShadowsSingleWindow = false. Is there a way and what's the best way to take full-resolution screenshots of the correct size? import Cocoa import ScreenCaptureKit class ViewController: NSViewController { @IBOutlet weak var imageView: NSImageView! override func viewDidAppear() { imageView.imageScaling = .scaleProportionallyUpOrDown view.wantsLayer = true view.layer!.backgroundColor = .init(red: 1, green: 0, blue: 0, alpha: 1) Task { let windows = try await SCShareableContent.excludingDesktopWindows(false, onScreenWindowsOnly: true).windows let window = windows[0] let filter = SCContentFilter(desktopIndependentWindow: window) let configuration = SCStreamConfiguration() configuration.ignoreShadowsSingleWindow = false configuration.showsCursor = false configuration.width = Int(Float(filter.contentRect.width) * filter.pointPixelScale) configuration.height = Int(Float(filter.contentRect.height) * filter.pointPixelScale) print(filter.contentRect) let windowImage = try await SCScreenshotManager.captureImage(contentFilter: filter, configuration: configuration) imageView.image = NSImage(cgImage: windowImage, size: CGSize(width: windowImage.width, height: windowImage.height)) } } }
5
0
946
Oct ’25
SKTexture used for SceneKit object is rendered too bright
I would like to preload and use some images for both SpriteKit and SceneKit models (my game uses SceneKit with a SpriteKit overlay), and as far as I can see the only efficient way would be to create and preload SKTexture objects which can be supplied to SKSpriteNode(texture:) and SCNMaterial.diffuse.contents. The problem is that SKTexture are rendered too bright in SceneKit, for some unknown reason. Here a comparison between rendering an image (from URL) and a SKTexture: And the code that produces it: let url = Bundle.main.url(forResource: "art.scnassets/texture.png", withExtension: nil)! let plane1 = SCNPlane(width: 10, height: 10) plane1.firstMaterial!.diffuse.contents = url.path let node1 = SCNNode(geometry: plane1) node1.position.x = -5 scene.rootNode.addChildNode(node1) let plane2 = SCNPlane(width: 10, height: 10) plane2.firstMaterial!.diffuse.contents = SKTexture(image: NSImage(byReferencing: url)) let node2 = SCNNode(geometry: plane2) node2.position.x = 5 scene.rootNode.addChildNode(node2) This issue was already mentioned in this other post, but since I wasn't notified of the reply from Quinn asking about the feedback number I created at the time, it didn't make any progress.
5
0
968
Nov ’24
NSTextView doesn't correctly redraw when deleting text and setting attribute at the same time
It seems that NSTextView has an issue with deleting text and setting any attribute at the same time, when it also has a textContainerInset. With the code below, after 1 second, the empty line in the text view is automatically deleted and the first line is colored red. The top part of the last line remains visible at its old position. Selecting the whole text and then deselecting it again makes the issue disappear. Is there a workaround? I've created FB16897003. class ViewController: NSViewController { @IBOutlet var textView: NSTextView! override func viewDidAppear() { textView.textContainerInset = CGSize(width: 0, height: 8) let _ = textView.layoutManager textView.textStorage!.setAttributedString(NSAttributedString(string: "1\n\n2\n3\n4")) textView.textStorage!.addAttribute(.foregroundColor, value: NSColor.labelColor, range: NSRange(location: 0, length: textView.textStorage!.length)) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [self] in textView.selectedRange = NSRange(location: 3, length: 0) textView.deleteBackward(nil) textView.textStorage!.beginEditing() textView.textStorage!.addAttribute(.foregroundColor, value: NSColor.red, range: NSRange(location: 0, length: 2)) textView.textStorage!.endEditing() } } }
5
0
293
Apr ’25
Overriding NSDocument.prepareSavePanel(_:) hides file format popup button
I would like to provide a default filename when saving a document depending on the document data. I thought I could do so by overriding NSDocument.prepareSavePanel(_:) and setting NSSavePanel.nameFieldStringValue, but simply implementing that method seems to hide the file format popup button shown by default (see image). Calling super doesn't help. Is it possible to set a default filename and keep the file format popup button? On macOS 15, I can toggle NSSavePanel.showsContentTypes, but how about macOS 14 and older?
Topic: UI Frameworks SubTopic: AppKit Tags:
5
0
248
Jan ’26
QLPreviewPanel takes forever to load content preview in macOS 26
After upgrading to macOS 26, I noticed that showing a Quicklook preview in my app is very slow. Showing small text files is fine, but some other files I've tried, such as a Numbers document, take about 30 seconds (during which the indeterminate loading indicator appears) before the preview is shown. When showing the preview of an app, such as Xcode, the panel opens immediately with a placeholder image for the Xcode icon, and the actual Xcode icon is shown only after about 25 seconds. During this time many logs appear: FPItemsFromURLsWithTimeout timed out (5.000000s) for: file:///.file/id=6571367.2/ (/) FPItemsFromURLsWithTimeout timed out (5.000000s) for: file:///.file/id=6571367.23684/ (/Users) FPItemsFromURLsWithTimeout timed out (5.000000s) for: file:///.file/id=6571367.248032/ (/Users/n{9}k) FPItemsFromURLsWithTimeout timed out (5.000000s) for: file:///.file/id=6571367.248084/ (/Users/n{9}k/Downloads) Failed to add registration dmf.policy.monitor.app with error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.dmd.policy was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.dmd.policy was invalidated: failed at lookup with error 159 - Sandbox restriction.} Failed to register application policy monitor with identifier 69DDBDB4-0736-42FA-BA7A-C8D7EA049E29 for types {( applicationcategories, websites, categories, applications )} with error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.dmd.policy was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.dmd.policy was invalidated: failed at lookup with error 159 - Sandbox restriction.} FPItemsFromURLsWithTimeout timed out (5.000000s) for: file:///.file/id=6571367.155797561/ (~/Downloads/X{3}e.app) It seems that Quicklook tries to access each parent directory of the previewed file, and each one fails after 5 seconds. Why is Quicklook all of a sudden so slow? It used to be almost instant in macOS 15. I created FB20268201. import Cocoa import Quartz @main class AppDelegate: NSObject, NSApplicationDelegate, QLPreviewPanelDataSource, QLPreviewPanelDelegate { var url: URL? func applicationDidFinishLaunching(_ notification: Notification) { let openPanel = NSOpenPanel() openPanel.runModal() url = openPanel.urls[0] QLPreviewPanel.shared()!.makeKeyAndOrderFront(nil) } override func acceptsPreviewPanelControl(_ panel: QLPreviewPanel!) -> Bool { return true } override func beginPreviewPanelControl(_ panel: QLPreviewPanel!) { panel.dataSource = self panel.delegate = self } override func endPreviewPanelControl(_ panel: QLPreviewPanel!) { panel.dataSource = nil panel.delegate = nil } func numberOfPreviewItems(in panel: QLPreviewPanel!) -> Int { return 1 } func previewPanel(_ panel: QLPreviewPanel!, previewItemAt index: Int) -> QLPreviewItem! { return url as? QLPreviewItem } }
5
1
345
Dec ’25
Xcode shows alert about unknown com.apple.quicklook.preview extension point when running on Apple Vision Pro Simulator
I have an iOS app with a QuickLook extension. I also added Apple Vision Pro in the target's General > Supported Destinations section. About one year ago, I was able to run the app on iPhone, iPad and Apple Vision Pro Simulators. Today I tried running it again on Apple Vision Pro with Xcode 26.0.1, but Xcode shows this error: Try again later. Appex bundle at ~/Library/Developer/CoreSimulator/Devices/F6B3CCA8-82FA-485F-A306-CF85FF589096/data/Library/Caches/com.apple.mobile.installd.staging/temp.PWLT59/extracted/problem.app/PlugIns/problemQuickLook.appex with id org.example.problem.problemQuickLook specifies a value (com.apple.quicklook.preview) for the NSExtensionPointIdentifier key in the NSExtension dictionary in its Info.plist that does not correspond to a known extension point. I tried again later a couple times, even after running Clean Build Folder Immediately, without any change. I can reproduce this with a fresh Xcode project to which I add a Quick Look Preview Extension and Apple Vision Pro as a supported destination. The error doesn't happen when running on Apple Vision Pro (Designed for iPad) or iPad Pro 13-inch (M4) destinations. What is the problem? I created FB20448815.
5
0
281
Nov ’25
NEFilterDataProvider.handleNewFlow(_:) gets called with same flow ids multiple times
Since NEFilterFlow.identifier is documented as The unique identifier of the flow., I thought I could use it to store the flow by its identifier in a dictionary in order to retrieve it later. I do this when the system extension pauses a flow because it needs to ask the user whether the flow should eventually be allowed or dropped. But then I noticed that sometimes when allowing a previously paused flow, identified by its identifier, my system extension doesn't find that flow anymore. After some debugging it turned out that this happens because I stored at least one other flow with the same id which, when confirmed, is removed again from the dictionary, so there is no more flow with that identifier waiting in the dictionary. Is it expected that the identifiers are recycled for different flows, or does it mean that the same flow is effectively being passed to .handleNewFlow(_:) multiple times, such as if the extension waited "too long" between pausing a flow and allowing or dropping it? What does this mean?
6
0
754
Nov ’23
Xcode downloads client crash reports for string interpolation (_StringGuts.append)
Xcode contains several crash reports downloaded from users of my app. Thread 1 apparently crashes while performing a string interpolation. All the other threads only contain calls to system code. The String.appendingPathComponent(_:) that appears in the stacktrace is defined as follows: extension String { func appendingPathComponent(_ pathComponent: String) -> String { return pathComponent == "" ? self : self == "" || self == "/" ? "\(self)\(pathComponent)" : "\(self)/\(pathComponent)" } } What could cause such a crash? Thread 1 Crashed: 0 CoreFoundation 0x00007ff81566f9df __CFStringEncodeByteStream + 120 (CFStringEncodings.c:692) 1 Foundation 0x00007ff8164c95aa -[NSString(NSStringOtherEncodings) getBytes:maxLength:usedLength:encoding:options:range:remainingRange:] + 204 (NSStringEncodings.m:341) 2 libswiftCore.dylib 0x00007ff822c6c1e0 String.UTF8View._foreignDistance(from:to:) + 208 (StringUTF8View.swift:507) 3 libswiftCore.dylib 0x00007ff822c56715 _StringGuts.append(_:) + 1445 (StringGutsRangeReplaceable.swift:191) 4 MyApp 0x00000001010c3c0f String.appendingPathComponent(_:) + 15 (<compiler-generated>:0)
6
0
799
Nov ’23
Xcode warning for call to DispatchQueue.main.sync: Call to method 'asd' in closure requires explicit use of 'self' to make capture semantics explicit
When calling DispatchQueue.main.async or DispatchQueue.main.sync with a call to self without capturing self, I get a compiler error: Call to method 'asd' in closure requires explicit use of 'self' to make capture semantics explicit Since I usually use DispatchQueue.main.async, I'm now used to solving this error by capturing self like this: DispatchQueue.main.async { [self] in asd() } But this unfortunately doesn't seem to work with DispatchQueue.main.sync: DispatchQueue.main.async { [self] in asd() } This gives the compiler warning: Call to method 'asd' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in Swift 6 This warning only appears for DispatchQueue.main.sync and not for DispatchQueue.main.async. Why? How can I avoid having to prefix every method call with self. in this case?
6
0
1.5k
Dec ’23