Construct and manage a graphical, event-driven user interface for your macOS app using AppKit.

Posts under AppKit tag

200 Posts

Post

Replies

Boosts

Views

Activity

NSOutlineView incorrectly draws disclosure indicator when item views are SwiftUI views.
I am using an NSOutlineView via NSViewRepresentable in a SwiftUI application running on macOS. Everything has been working fine. Up until lately, I've been returning a custom NSView for each item using the standard: func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { // View recycling omitted. return MyItemView(item) } Now I want to explore using a little bit more SwiftUI and returning an NSHostingView from this delegate method. func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { // View recycling omitted. let rootView = MySwiftUIView(item) let hostingView = NSHostingView(rootView: rootView) return hostingView } For the most part, this appears to be working fine. NSOutlineView is even correctly applying highlight styling, so that's great. But there's one small glitch. The outline view's disclosure triangles do not align with the hosting view's content. The disclosure triangles appear to just be pinned to the top. Perhaps they can't find a baseline constraint or something? Is there any SwiftUI modifier or AppKit/SwiftUI technique I can apply here to get the disclosure button to appear in the right place? Here is what the SwiftUI + NSHostingView version looks like: Note the offset disclosure indicators. (Image spacing is a bit off as well using Label, but fixable. Here is what an NSView with NSTextFields looks like: Disclosure indicators are correctly aligned, as you would expect.
1
0
293
Nov ’25
AVAssetExportSession ignores frameDuration 60fps and exports at 30fps, but AVPlayer playback is correct
Hey everyone, I'm stuck on a really frustrating AVFoundation problem. I'm building a video editor that uses a custom AVVideoCompositor to add effects, and I need the final output to be 60 FPS. So basically, I create an AVMutableComposition to sequence my video clips. I create an AVMutableVideoComposition and set the frame rate to 60 FPS: videoComposition.frameDuration = CMTime(value: 1, timescale: 60) I assign my CustomVideoCompositor class to the videoComposition. I create an AVPlayerItem with the composition and video composition. The Problem: Playback Works: When I play the AVPlayerItem in an AVPlayer, it's perfect. It plays at a smooth 60 FPS, and my custom compositor's startRequest method is called 60 times per second. Export Fails: When I try to export the exact same composition and video composition using AVAssetExportSession, the final .mp4 file is always 30 FPS (or 29.97). I've logged inside my custom compositor during the export, and it's definitely being called 30 times per second, so it's generating the 30 frames. It seems like AVAssetExportSession is just dropping every other frame when it encodes the video. My source videos are screen recordings which I recorded using ScreenCaptureKit itself with the minimum frame interval to be 60. Here is my export function. I'm using the AVAssetExportPresetHighestQuality preset :- func exportVideo(to outputURL: URL) async throws { guard let composition = composition, let videoComposition = videoComposition else { throw VideoCompositionError.noValidVideos } try? FileManager.default.removeItem(at: outputURL) guard let exportSession = AVAssetExportSession( asset: composition, presetName: AVAssetExportPresetHighestQuality // Is this the problem? ) else { throw VideoCompositionError.trackCreationFailed } exportSession.outputFileType = .mp4 exportSession.videoComposition = videoComposition // This has the 60fps setting try await exportSession.export(to: outputURL, as: .mp4) } I've created a bare bones sample project that shows this exact bug in action. The resulting video is 60fps during playback, but only 30fps during the export. https://github.com/zaidbren/SimpleEditor My Question: Why is AVAssetExportSession ignoring my 60 FPS frameDuration and defaulting to 30 FPS, even though AVPlayer respects it?
1
0
838
Oct ’25
Prevent default file selector in a SwiftUI DocumentGroup app and show a custom welcome window on launch
I’m building a macOS document based app using SwiftUI’s DocumentGroup API. By default, when a document based app launches, macOS automatically shows a file open panel or creates a new untitled document window. However, I want to suppress this default behavior and instead show a custom welcome window when the app starts — something similar to how Xcode or Final Cut Pro shows a “Welcome” or “Start Project” screen first. So basically, when the user opens the app normally, it should not open the document selector or create a document automatically. Instead, it should show my custom SwiftUI or AppKit window. Here is my Code :- //MyApp.swift import SwiftUI import AppKit @main struct PhiaApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { DocumentGroup(newDocument: MyDocumentModel()) { file in EditorView(document: file.document, filePath: file.fileURL) } Settings { EmptyView() } } } Current I have this code setup for my MainApp.swift, where I am using the AppDelegate to create a custom recording window using appkit and also defining the DocumentGroup to handle the custom .myapp file opens. However, when I launch the app, its showing my appkit window as well as the macOs native file Selector to select the file I want to open. I want when the user opens the app normally, it should not open the document selector or create a document automatically. Instead, it should show my custom SwiftUI or AppKit window. However, the app should still fully support opening .myapp documents by double clicking from Finder, using the standard File → Open and File → New menu options, also having multiple document windows open at once. This is my AppDelegate.swift file :- import AppKit import SwiftUI class AppDelegate: NSObject, NSApplicationDelegate { var panel: Panel? private var statusItem: NSStatusItem? func applicationDidFinishLaunching(_ notification: Notification) { showWindow() } // MARK: - Window control func showWindow() { if panel == nil { let root = RecordingViewMain() let newPanel = Panel(rootView: root) if let screen = NSScreen.main { let size = NSSize(width: 360, height: 240) let origin = NSPoint( x: screen.visibleFrame.midX - size.width / 2, y: screen.visibleFrame.midY - size.height / 2 ) newPanel.setFrame(NSRect(origin: origin, size: size), display: true) } panel = newPanel } panel?.makeKeyAndOrderFront(nil) } func hideWindow() { panel?.orderOut(nil) } @objc private func showPanelAction() { showWindow() } @objc private func quitAction() { NSApp.terminate(nil) } }
2
0
463
Oct ’25
Value of type 'SCRecordingOutput' has no member 'delegate'
Hello, I am trying to capture screen recording ( output.mp4 ) using ScreenCaptureKit and also the mouse positions during the recording ( mouse.json ). The recording and the mouse positions ( tracked based on mouse movements events only ) needs to be perfectly synced in order to add effects in post editing. I started off by using the await stream?.startCapture() and after that starting my mouse tracking function :- try await captureEngine.startCapture(configuration: config, filter: filter, recordingOutput: recordingOutput) let captureStartTime = Date() mouseTracker?.startTracking(with: captureStartTime) But every time I tested, there is a clear inconsistency in sync between the recorded video and the recorded mouse positions. The only thing I want is to know when exactly does the recording "actually" started so that I can start the mouse capture at that same time, and thus I tried using the Delegates, but being able to set them up perfectly. import Foundation import AVFAudio import ScreenCaptureKit import OSLog import Combine class CaptureEngine: NSObject, @unchecked Sendable { private let logger = Logger() private(set) var stream: SCStream? private var streamOutput: CaptureEngineStreamOutput? private var recordingOutput: SCRecordingOutput? private let videoSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.VideoSampleBufferQueue") private let audioSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.AudioSampleBufferQueue") private let micSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.MicSampleBufferQueue") func startCapture(configuration: SCStreamConfiguration, filter: SCContentFilter, recordingOutput: SCRecordingOutput) async throws { // Create the stream output delegate. let streamOutput = CaptureEngineStreamOutput() self.streamOutput = streamOutput do { stream = SCStream(filter: filter, configuration: configuration, delegate: streamOutput) try stream?.addStreamOutput(streamOutput, type: .screen, sampleHandlerQueue: videoSampleBufferQueue) try stream?.addStreamOutput(streamOutput, type: .audio, sampleHandlerQueue: audioSampleBufferQueue) try stream?.addStreamOutput(streamOutput, type: .microphone, sampleHandlerQueue: micSampleBufferQueue) self.recordingOutput = recordingOutput recordingOutput.delegate = self try stream?.addRecordingOutput(recordingOutput) try await stream?.startCapture() } catch { logger.error("Failed to start capture: \(error.localizedDescription)") throw error } } func stopCapture() async throws { do { try await stream?.stopCapture() } catch { logger.error("Failed to stop capture: \(error.localizedDescription)") throw error } } func update(configuration: SCStreamConfiguration, filter: SCContentFilter) async { do { try await stream?.updateConfiguration(configuration) try await stream?.updateContentFilter(filter) } catch { logger.error("Failed to update the stream session: \(String(describing: error))") } } func stopRecordingOutputForStream(_ recordingOutput: SCRecordingOutput) throws { try self.stream?.removeRecordingOutput(recordingOutput) } } // MARK: - SCRecordingOutputDelegate extension CaptureEngine: SCRecordingOutputDelegate { func recordingOutputDidStartRecording(_ recordingOutput: SCRecordingOutput) { let startTime = Date() logger.info("Recording output did start recording \(startTime)") } func recordingOutputDidFinishRecording(_ recordingOutput: SCRecordingOutput) { logger.info("Recording output did finish recording") } func recordingOutput(_ recordingOutput: SCRecordingOutput, didFailWithError error: any Error) { logger.error("Recording output failed with error: \(error.localizedDescription)") } } private class CaptureEngineStreamOutput: NSObject, SCStreamOutput, SCStreamDelegate { private let logger = Logger() override init() { super.init() } func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of outputType: SCStreamOutputType) { guard sampleBuffer.isValid else { return } switch outputType { case .screen: break case .audio: break case .microphone: break @unknown default: logger.error("Encountered unknown stream output type:") } } func stream(_ stream: SCStream, didStopWithError error: Error) { logger.error("Stream stopped with error: \(error.localizedDescription)") } } I am getting error Value of type 'SCRecordingOutput' has no member 'delegate' Even though I am targeting macOs 15+ ( macOs 26 actually ) and macOs only. What is the best way to achieving the desired result? Is there any other / better way to do it?
1
0
621
Oct ’25
NSScrollView only scrolls vertically for NSTableView after window resize
Hi everyone, I’m looking for help with an issue where using insertRows to add a row to an NSTableView requires resizing the window before I can scroll to the newly added rows that extend beyond the visible area of the NSScrollView. import Cocoa class ViewController: NSViewController { var data = Constants.movies // Table components var titleField = NSTextField() var directorField = NSTextField() var releaseYearField = NSTextField() var addMovieButton = NSButton(title: "Add Movie", image: NSImage(systemSymbolName: "plus", accessibilityDescription: "")!, target: nil, action: #selector(addMovie)) var table = NSTableView() var titleColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.titleColumnId)) var directorColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.directorColumnId)) var releaseYearColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.releaseColumnId)) // Scroll view let scrollView = NSScrollView() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. view.wantsLayer = true view.layer?.backgroundColor = NSColor.black.cgColor configure() } private func configure() { titleField.translatesAutoresizingMaskIntoConstraints = false directorField.translatesAutoresizingMaskIntoConstraints = false releaseYearField.translatesAutoresizingMaskIntoConstraints = false addMovieButton.translatesAutoresizingMaskIntoConstraints = false scrollView.translatesAutoresizingMaskIntoConstraints = false table.translatesAutoresizingMaskIntoConstraints = false titleField.placeholderString = "Movie Title" directorField.placeholderString = "Name of Director" releaseYearField.placeholderString = "Year Released" // Configure table table.addTableColumn(titleColumn) table.addTableColumn(directorColumn) table.addTableColumn(releaseYearColumn) titleColumn.title = "Movie Title" directorColumn.title = "Director" releaseYearColumn.title = "Year Released" table.delegate = self table.dataSource = self table.focusRingType = .none // Configure scroll view scrollView.documentView = table scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = false scrollView.autohidesScrollers = true // Add views to the hierarchy view.addSubview(titleField) view.addSubview(directorField) view.addSubview(releaseYearField) view.addSubview(addMovieButton) view.addSubview(scrollView) // view.addSubview(table) NSLayoutConstraint.activate([ titleField.widthAnchor.constraint(equalToConstant: 150), directorField.widthAnchor.constraint(equalToConstant: 150), releaseYearField.widthAnchor.constraint(equalToConstant: 150), addMovieButton.widthAnchor.constraint(equalToConstant: 100), titleField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), directorField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), releaseYearField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), addMovieButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), directorField.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant: -10), releaseYearField.leadingAnchor.constraint(equalTo: view.centerXAnchor, constant: 10), titleField.trailingAnchor.constraint(equalTo: directorField.leadingAnchor, constant: -20), addMovieButton.leadingAnchor.constraint(equalTo: releaseYearField.trailingAnchor, constant: 20), scrollView.topAnchor.constraint(equalTo: titleField.bottomAnchor, constant: 20), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20), // table.widthAnchor.constraint(equalTo: scrollView.contentView.widthAnchor), // table.heightAnchor.constraint(equalTo: scrollView.contentView.heightAnchor) ]) } @objc private func addMovie() { let title = titleField.stringValue let director = directorField.stringValue guard let year = Int(releaseYearField.stringValue) else { return } let movie = Movie(title: title, director: director, releaseYear: year) data.append(movie) // Approach 1 // table.reloadData() // Approach 2 let newRow = data.count - 1 table.insertRows(at: IndexSet(integer: newRow), withAnimation: .slideDown) } Using table.reloadData works fine and I can scroll to the new rows as I add them, but it doesn't have the smooth animation I want to achieve. What is the best practice and correct way for using table.insertRows to avoid this issue? Note: I am using programmatic constraints only.
1
0
675
Oct ’25
SwiftUI buttons behind NSToolbarView are not clickable on macOS 26 beta
Overview Starting with macOS 26 beta 1, a new NSGlassContainerView is added inside NSToolbarView. This view intercepts mouse events, so any SwiftUI Button (or other interactive view) overlaid on the title‑bar / toolbar area no longer receives clicks. (The same code works fine on macOS 15 and earlier.) Filed as FB18201935 via Feedback Assistant. Reproduction (minimal project) macOS 15 or earlier → button is clickable macOS 26 beta → button cannot be clicked (no highlight, no action call) @main struct Test_macOS26App: App { init() { // Uncomment to work around the issue (see next section) // enableToolbarClickThrough() } var body: some Scene { WindowGroup { ContentView() } .windowStyle(.hiddenTitleBar) // ⭐️ hide the title bar } } struct ContentView: View { var body: some View { NavigationSplitView { List { Text("sidebar") } } detail: { HSplitView { listWithOverlay listWithOverlay } } } private var listWithOverlay: some View { List(0..<30) { Text("item: \($0)") } .overlay(alignment: .topTrailing) { // ⭐️ overlay in the toolbar area Button("test") { print("test") } .glassEffect() .ignoresSafeArea() } } } Investigation In Xcode View Hierarchy Debugger, a layer chain NSToolbarView > NSGlassContainerView sits in front of the button. -[NSView hitTest:] on NSGlassContainerView returns itself, so the event never reaches the SwiftUI layer. Swizzling hitTest: to return nil when the result is the view itself makes the click go through: func enableToolbarClickThrough() { guard let cls = NSClassFromString("NSGlassContainerView"), let m = class_getInstanceMethod(cls, #selector(NSView.hitTest(_:))) else { return } typealias Fn = @convention(c)(AnyObject, Selector, NSPoint) -> Unmanaged<NSView>? let origIMP = unsafeBitCast(method_getImplementation(m), to: Fn.self) let block: @convention(block)(AnyObject, NSPoint) -> NSView? = { obj, pt in guard let v = origIMP(obj, #selector(NSView.hitTest(_:)), pt)?.takeUnretainedValue() else { return nil } return v === (obj as AnyObject) ? nil : v // ★ make the container transparent } method_setImplementation(m, imp_implementationWithBlock(block)) } Questions / Call for Feedback Is this an intentional behavioral change? If so, what is the recommended public API or pattern for allowing clicks to reach views overlaid behind the toolbar? Any additional data points or confirmations are welcome—please reply if you can reproduce the issue or know of an official workaround. Thanks in advance!
3
0
699
Oct ’25
What is the standard process of subclassing NSTextLocation?
Cannot find any guidance in the forums and Developer Doc, the WWDC session Meet TextKit2 says this protocol is served for any location type espacially useful when the underlying doc model is not linear. But when I try to subclass the NSTextLocation with my own type to define a more structured location rather than a linear one, also with my own NSTextContentManager subclass implementation, I keep receiving the system internal Location model like NSCountableTextLocation compare to my location which cause the app to crash. -[NSCountableTextLocation compare:] receiving unmatching type <MarkdownTK2.ChildIndexPathLocation: 0x9b2402aa0> In my own NSTextContentManager subclass: public override func offset( from: any NSTextLocation, to: any NSTextLocation ) -> Int { this method will also both receive my own location and some times receiving the system defined location that I can not calculate the offset then just return zero. The doc only says If you provide your own implementation of the NSTextLocation protocol to manage locations in your content, subclass NSTextContentManager and implement your own storage object to support those locations. OS Development environment: Xcode 26.0, macOS 26.0 Run-time configuration: macOS 26.0
3
0
729
Oct ’25
Xcode 26 Compiler Critical Issues?
Hello everyone, Since I installed Xcode 26, I've been encountering issues I've never seen before. I have Mac OS applications written in Objective-C, some released as far back as 14 years ago. When compiling them with Xcode 26, I experience efficiency issues related to thread management and interface updates. There are rendering problems with a simple NSTextView created through Interface Builder. The issue is not easily reproducible as it occurs randomly on some machines, regardless of their architecture or macOS version. The main thread freezes, and generally after 15-30 seconds, it unfreezes, loading the interface and text. The length of the text is irrelevant to the issue, and no crashes occur. I spent ten days trying to optimize the code and change the loading order within the class, but the problem persists. However, if I compile the application with Xcode 16.4, everything works like a charm. I also tried using the macOS 15.5 SDK to compile with Xcode 26, but it doesn’t resolve any issues. Additionally, I tried changing the compiler optimization level, but it didn’t solve the problem. This leads me to believe it’s an issue with the Xcode 26 compiler. If it were a code issue, it would be easily reproducible and would also occur when compiling with 16.4. The Xcode 26.1 Beta doesn’t resolve the issue. Can anyone tell me if I need to change something related to the compiler? Are you aware of any issues like this? Thank you, Luca
0
1
628
Oct ’25
XPC: too many nested collections when explicitly decoding a single collection on macOS 12.7 (not on macOS Tahoe)
I have a custom object which gets passed back to the main app from XPC. I whitelist it like so: NSSet *expectedClass = [NSSet setWithObjects:[NSArray class], [MyCustomClass class], nil]; [interface setClasses:expectedClass forSelector:@selector(myMethodNameHere:withCompletion:) argumentIndex:0 ofReply:YES]; Now my custom class conforms to NSSecureCoding. It does have an array property of another custom class. @property (nonatomic,readonly) NSArray *arraypropertyOfOtherClass; Which is decoded in -initWithCoder: using: -decodeArrayOfObjectsOfClasses:forKey: Now on macOS Tahoe this is all walking fine. But I just tested on macOS Monterey and I get the following error: Exception: decodeObjectForKey: too many nested collections when explicitly decoding a single collection. How should I handle this for earlier versions of macOS?
2
0
625
Oct ’25
How to bind AppKit window to Observable viewmodel using SwiftUI app life cycle
Hey everyone. I have a macOS app written in SwiftUI. I have multiple SwiftUI Scenes and Views, but needed to write one specific window in AppKit (an NSPanel, to be specific). The problem I'm facing is- I'm not sure how to incorporate this NSPanel with the rest of my SwiftUI/Observable code. I'm relying on the SwiftUI app cycle. For example, I have a boolean in my view model (observation tracked). I'd like to use this boolean to hide/unhide my NSPanel. Any way to cleanly hook into the viewmodel, or onto some specific observable variables would be very very helpful. Thank you everyone.
1
0
330
Oct ’25
[NSEvent charactersByApplyingModifiers:] not matching NSEvent.characters/charactersIgnoringModifiers
To my surprise [NSEvent charactersByApplyingModifiers:] does not always produce the same NSString result as the originating NSEvent reflects through characters/charactersIgnoringModifiers, even if passing on the event's own modifierFlags. For example, when pressing the 'end' key, both characters and charactersIgnoringModifiers return 0x000000000000f72b, which matches the value of NSEndFunctionKey. But calling [NSEvent charactersByApplyingModifiers:] passing in NSEvent.modifierFlags produces 0x0000000000000004, which matches the value of kEndCharCode. (lldb) po [[((NSApplication*)NSApp).currentEvent characters] characterAtIndex:0] 0x000000000000f72b (lldb) po [[((NSApplication*)NSApp).currentEvent charactersIgnoringModifiers] characterAtIndex:0] 0x000000000000f72b (lldb) po [[((NSApplication*)NSApp).currentEvent charactersByApplyingModifiers:[(NSEvent*)((NSApplication*)NSApp).currentEvent modifierFlags]] characterAtIndex:0] 0x0000000000000004 (The same can be observed with UCKeyTranslate directly, which charactersByApplyingModifiers seems to use internally). I would expect [NSApp.currentEvent charactersByApplyingModifiers:NSApp.currentEvent.modifierFlags] to match either NSApp.currentEvent.characters or NSApp.currentEvent.charactersIgnoringModifiers. Is there a logic behind this perceived discrepancy that I'm missing? Should I always prefer the content of NSEvent.characters/charactersIgnoringModifiers in this case if the modifier flags I'm applying match those of the event itself? Thanks for any insights! (Also reported as FB20591338)
Topic: UI Frameworks SubTopic: AppKit Tags:
3
0
276
Oct ’25
Resize Window Form After Loading
I am trying to resize a Window Form after it loads and have done quite a bit of searching for code to do it. Here is one code snippet that works to size the form during the design phase. self.view.window?.contentMinSize = CGSize(width: 1100, height: 310) I have tried code like below to increase the window size after the Form loads if let myWindow = self.view.window ?? NSApplication.shared.mainWindow { // Increase window size and position after it loads let newRect = NSRect(x: 100, y: 100, width: 1400, height: 900) } It seems that this code not only changes the Form size after loading, but also changes the size of the Form in Main.swift, which is something I don't want. I read elsewhere that I had to disable constraints to resize the Form, so I tried code below. let tableView = NSTableView() tableView.translatesAutoresizingMaskIntoConstraints = false let newRect = NSRect(x: 100, y: 0, width: 1100, height: 600) myWindow?.setFrame(newRect, display: true) That code did not seem to do anything as well. Also, the Form displays in the lower left of the screen. Note that main reason I want to resize the Form after loading is to keep it smaller during design development. The same goes for the NSTableView, which I have not gotten to yet.
0
0
332
Oct ’25
NSHostingSceneRepresentation doesn't show Window(_:id:) and UtilityWindow(_:id:) with .openWIndow(id:)
NSHostingSceneRepresentation, introduced in macOS 26, allows calling SwiftUI’s windows and other elements set in a Scene from AppKit. However, while Settings and WindowGroup set in the Scene can be invoked as expected using environment.openSettings() and environment.openWindow(id:) respectively, calling Window or WindowUtility doesn’t work. That is, the app just fails to open the desired window with the provided ID, and no error message or other feedback/crash/freeze appears. I expect that executing the openUtilityWindow(_:)action in the following code will display the UtilityWindow set in the scene. However, the window does not actually open. @main final class AppDelegate: NSObject, NSApplicationDelegate { private let scene = NSHostingSceneRepresentation { UtilityWindow("Utility Window", id: "UtilityWindow") { Text("Utility Window") .scenePadding() } } func applicationWillFinishLaunching(_ notification: Notification) { NSApp.addSceneRepresentation(self.scene) } @IBAction func openUtilityWindow(_ sender: Any?) { self.scene.environment.openWindow(id: "UtilityWindow") } } Is there something wrong with my implementation and expectation? Or is this a bug in NSHostingSceneRepresentation? Just in case, I’ve already filed this issue withFeedback Assistant: FB20310722 This feedback also includes a sample project reproducing this issue.
1
1
482
Oct ’25
Why does AppStore.requestReview(in:) require NSViewController Parameter?
Looking to update one of my apps that uses SKStoreReviewController +requestReview (deprecated) to AppStore.requestReview(in:) umm...I have a few of questions... Why is an NSViewController parameter required? It's really not so uncommon for an AppKit app to just use NSWindowController with a window that does not use NSViewController... It should be possible to present the review request in a standalone alert (attached to a window is preferred IMO but it still should be possible to ask in separate window). 3)...why Swift..(err nevermind) Ideally: AppStore requestReview should take a NSWindow parameter but that parameter should be optional. If nil the request should be presented in a standalone window (like an alert). If non nil..present as a sheet on the window. Why a view controller? Maybe I'm missing something.
2
0
344
Oct ’25
Grammar checking is never requested
I have prepared a NSSpellServer spelling and grammar checker for Slovenian proofing in macOS. My proofing service gets used when I explicitly set keyboard spelling language to "Slovenian (Besana)" (my proofing service). However, no matter how I set the Check Grammar With Spelling option or Check Grammar checkbox in the TextEdit.app or Mail.app, my proofing service does not get any request for grammar checking. I am supporting checkString call for Unified checking and checkingTypes never contains NSTextCheckingTypeGrammar flag. When using legacy API before Unified checking support, the checkGrammarInString is never called either. If I do the grammar regardless the checkingTypes parameter, the app shows grammar mistakes correctly. But that is bad UX. Need to follow user demand for with grammar or without grammar. I don't know what am I doing wrong? On my home iMac v11 it actually works. No idea what I did there to make it work. Just worked. On my working Mac Mini v13 it won't check grammar. On another MacBook Pro v15, it won't check grammar either. Apps do check spelling with my proofing service. But not grammar. Same apps do grammar checking with stock AppleSpelling.service just fine. I have checked my Info.plist, using Hardened Runtime, have empty Entitlements, to no avail. Was there some new grammar API introduced after macOS v11 Big Sur, I should implement? Is there some specific Entitlement, signature, notarization I should perform to get going? Some documentation I am missing?
2
0
417
Oct ’25
ProgressView Tint doesn't work on macOS
I seem to be unable to affect the color of a linear ProgressView() on macOS and need to know if this is a feature or a bug. I have the following: ProgressView(value: someProgress).tint(.green) This works fine in iOS, the linear ProgressView changes to the desired color. On macOS the ProgressView stays the color of the system accent. .progressViewStyle(LinearProgressViewStyle(tint: .blue)) Is available, but depreciated, or being depreciated. I have also tried: .tint(.red) .accentColor(.green) While I can understand the platform specific differences, the context that I'm using really would benefit from keeping the UI elements colored consistent with the app, rather than the OS. Also I can do it in iOS, why not macOS? Both dev and test machines are running latest updates (Xcode 26.0.1/macOS 26.0.1 and iOS 26.0.1/macOS26.0.1)
3
0
288
Oct ’25
NSDocument doesn't autosave last changes
I had noticed an unsettling behaviour about NSDocument some years ago and created FB7392851, but the feedback didn't go forward, so I just updated it and hopefully here or there someone can explain what's going on. When running a simple document-based app with a text view, what I type before closing the app may be discarded without notice. To reproduce it, you can use the code below, then: Type "asdf" in the text view. Wait until the Xcode console logs "saving". You can trigger it by switching to another app and back again. Type something else in the text view, such as "asdf" on a new line. Quit the app. Relaunch the app. The second line has been discarded. Am I doing something wrong or is this a bug? Is there a workaround? class ViewController: NSViewController { @IBOutlet var textView: NSTextView! } class Document: NSDocument { private(set) var text = "" override class var autosavesInPlace: Bool { return true } override func makeWindowControllers() { let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil) let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! NSWindowController (windowController.contentViewController as? ViewController)?.textView.string = text self.addWindowController(windowController) } override func data(ofType typeName: String) throws -> Data { Swift.print("saving") text = (windowControllers.first?.contentViewController as? ViewController)?.textView.string ?? "" return Data(text.utf8) } override func read(from data: Data, ofType typeName: String) throws { text = String(decoding: data, as: UTF8.self) (windowControllers.first?.contentViewController as? ViewController)?.textView.string = text } }
Topic: UI Frameworks SubTopic: AppKit Tags:
17
0
808
Oct ’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
480
Sep ’25
NSOutlineView incorrectly draws disclosure indicator when item views are SwiftUI views.
I am using an NSOutlineView via NSViewRepresentable in a SwiftUI application running on macOS. Everything has been working fine. Up until lately, I've been returning a custom NSView for each item using the standard: func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { // View recycling omitted. return MyItemView(item) } Now I want to explore using a little bit more SwiftUI and returning an NSHostingView from this delegate method. func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { // View recycling omitted. let rootView = MySwiftUIView(item) let hostingView = NSHostingView(rootView: rootView) return hostingView } For the most part, this appears to be working fine. NSOutlineView is even correctly applying highlight styling, so that's great. But there's one small glitch. The outline view's disclosure triangles do not align with the hosting view's content. The disclosure triangles appear to just be pinned to the top. Perhaps they can't find a baseline constraint or something? Is there any SwiftUI modifier or AppKit/SwiftUI technique I can apply here to get the disclosure button to appear in the right place? Here is what the SwiftUI + NSHostingView version looks like: Note the offset disclosure indicators. (Image spacing is a bit off as well using Label, but fixable. Here is what an NSView with NSTextFields looks like: Disclosure indicators are correctly aligned, as you would expect.
Replies
1
Boosts
0
Views
293
Activity
Nov ’25
AVAssetExportSession ignores frameDuration 60fps and exports at 30fps, but AVPlayer playback is correct
Hey everyone, I'm stuck on a really frustrating AVFoundation problem. I'm building a video editor that uses a custom AVVideoCompositor to add effects, and I need the final output to be 60 FPS. So basically, I create an AVMutableComposition to sequence my video clips. I create an AVMutableVideoComposition and set the frame rate to 60 FPS: videoComposition.frameDuration = CMTime(value: 1, timescale: 60) I assign my CustomVideoCompositor class to the videoComposition. I create an AVPlayerItem with the composition and video composition. The Problem: Playback Works: When I play the AVPlayerItem in an AVPlayer, it's perfect. It plays at a smooth 60 FPS, and my custom compositor's startRequest method is called 60 times per second. Export Fails: When I try to export the exact same composition and video composition using AVAssetExportSession, the final .mp4 file is always 30 FPS (or 29.97). I've logged inside my custom compositor during the export, and it's definitely being called 30 times per second, so it's generating the 30 frames. It seems like AVAssetExportSession is just dropping every other frame when it encodes the video. My source videos are screen recordings which I recorded using ScreenCaptureKit itself with the minimum frame interval to be 60. Here is my export function. I'm using the AVAssetExportPresetHighestQuality preset :- func exportVideo(to outputURL: URL) async throws { guard let composition = composition, let videoComposition = videoComposition else { throw VideoCompositionError.noValidVideos } try? FileManager.default.removeItem(at: outputURL) guard let exportSession = AVAssetExportSession( asset: composition, presetName: AVAssetExportPresetHighestQuality // Is this the problem? ) else { throw VideoCompositionError.trackCreationFailed } exportSession.outputFileType = .mp4 exportSession.videoComposition = videoComposition // This has the 60fps setting try await exportSession.export(to: outputURL, as: .mp4) } I've created a bare bones sample project that shows this exact bug in action. The resulting video is 60fps during playback, but only 30fps during the export. https://github.com/zaidbren/SimpleEditor My Question: Why is AVAssetExportSession ignoring my 60 FPS frameDuration and defaulting to 30 FPS, even though AVPlayer respects it?
Replies
1
Boosts
0
Views
838
Activity
Oct ’25
Prevent default file selector in a SwiftUI DocumentGroup app and show a custom welcome window on launch
I’m building a macOS document based app using SwiftUI’s DocumentGroup API. By default, when a document based app launches, macOS automatically shows a file open panel or creates a new untitled document window. However, I want to suppress this default behavior and instead show a custom welcome window when the app starts — something similar to how Xcode or Final Cut Pro shows a “Welcome” or “Start Project” screen first. So basically, when the user opens the app normally, it should not open the document selector or create a document automatically. Instead, it should show my custom SwiftUI or AppKit window. Here is my Code :- //MyApp.swift import SwiftUI import AppKit @main struct PhiaApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { DocumentGroup(newDocument: MyDocumentModel()) { file in EditorView(document: file.document, filePath: file.fileURL) } Settings { EmptyView() } } } Current I have this code setup for my MainApp.swift, where I am using the AppDelegate to create a custom recording window using appkit and also defining the DocumentGroup to handle the custom .myapp file opens. However, when I launch the app, its showing my appkit window as well as the macOs native file Selector to select the file I want to open. I want when the user opens the app normally, it should not open the document selector or create a document automatically. Instead, it should show my custom SwiftUI or AppKit window. However, the app should still fully support opening .myapp documents by double clicking from Finder, using the standard File → Open and File → New menu options, also having multiple document windows open at once. This is my AppDelegate.swift file :- import AppKit import SwiftUI class AppDelegate: NSObject, NSApplicationDelegate { var panel: Panel? private var statusItem: NSStatusItem? func applicationDidFinishLaunching(_ notification: Notification) { showWindow() } // MARK: - Window control func showWindow() { if panel == nil { let root = RecordingViewMain() let newPanel = Panel(rootView: root) if let screen = NSScreen.main { let size = NSSize(width: 360, height: 240) let origin = NSPoint( x: screen.visibleFrame.midX - size.width / 2, y: screen.visibleFrame.midY - size.height / 2 ) newPanel.setFrame(NSRect(origin: origin, size: size), display: true) } panel = newPanel } panel?.makeKeyAndOrderFront(nil) } func hideWindow() { panel?.orderOut(nil) } @objc private func showPanelAction() { showWindow() } @objc private func quitAction() { NSApp.terminate(nil) } }
Replies
2
Boosts
0
Views
463
Activity
Oct ’25
Value of type 'SCRecordingOutput' has no member 'delegate'
Hello, I am trying to capture screen recording ( output.mp4 ) using ScreenCaptureKit and also the mouse positions during the recording ( mouse.json ). The recording and the mouse positions ( tracked based on mouse movements events only ) needs to be perfectly synced in order to add effects in post editing. I started off by using the await stream?.startCapture() and after that starting my mouse tracking function :- try await captureEngine.startCapture(configuration: config, filter: filter, recordingOutput: recordingOutput) let captureStartTime = Date() mouseTracker?.startTracking(with: captureStartTime) But every time I tested, there is a clear inconsistency in sync between the recorded video and the recorded mouse positions. The only thing I want is to know when exactly does the recording "actually" started so that I can start the mouse capture at that same time, and thus I tried using the Delegates, but being able to set them up perfectly. import Foundation import AVFAudio import ScreenCaptureKit import OSLog import Combine class CaptureEngine: NSObject, @unchecked Sendable { private let logger = Logger() private(set) var stream: SCStream? private var streamOutput: CaptureEngineStreamOutput? private var recordingOutput: SCRecordingOutput? private let videoSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.VideoSampleBufferQueue") private let audioSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.AudioSampleBufferQueue") private let micSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.MicSampleBufferQueue") func startCapture(configuration: SCStreamConfiguration, filter: SCContentFilter, recordingOutput: SCRecordingOutput) async throws { // Create the stream output delegate. let streamOutput = CaptureEngineStreamOutput() self.streamOutput = streamOutput do { stream = SCStream(filter: filter, configuration: configuration, delegate: streamOutput) try stream?.addStreamOutput(streamOutput, type: .screen, sampleHandlerQueue: videoSampleBufferQueue) try stream?.addStreamOutput(streamOutput, type: .audio, sampleHandlerQueue: audioSampleBufferQueue) try stream?.addStreamOutput(streamOutput, type: .microphone, sampleHandlerQueue: micSampleBufferQueue) self.recordingOutput = recordingOutput recordingOutput.delegate = self try stream?.addRecordingOutput(recordingOutput) try await stream?.startCapture() } catch { logger.error("Failed to start capture: \(error.localizedDescription)") throw error } } func stopCapture() async throws { do { try await stream?.stopCapture() } catch { logger.error("Failed to stop capture: \(error.localizedDescription)") throw error } } func update(configuration: SCStreamConfiguration, filter: SCContentFilter) async { do { try await stream?.updateConfiguration(configuration) try await stream?.updateContentFilter(filter) } catch { logger.error("Failed to update the stream session: \(String(describing: error))") } } func stopRecordingOutputForStream(_ recordingOutput: SCRecordingOutput) throws { try self.stream?.removeRecordingOutput(recordingOutput) } } // MARK: - SCRecordingOutputDelegate extension CaptureEngine: SCRecordingOutputDelegate { func recordingOutputDidStartRecording(_ recordingOutput: SCRecordingOutput) { let startTime = Date() logger.info("Recording output did start recording \(startTime)") } func recordingOutputDidFinishRecording(_ recordingOutput: SCRecordingOutput) { logger.info("Recording output did finish recording") } func recordingOutput(_ recordingOutput: SCRecordingOutput, didFailWithError error: any Error) { logger.error("Recording output failed with error: \(error.localizedDescription)") } } private class CaptureEngineStreamOutput: NSObject, SCStreamOutput, SCStreamDelegate { private let logger = Logger() override init() { super.init() } func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of outputType: SCStreamOutputType) { guard sampleBuffer.isValid else { return } switch outputType { case .screen: break case .audio: break case .microphone: break @unknown default: logger.error("Encountered unknown stream output type:") } } func stream(_ stream: SCStream, didStopWithError error: Error) { logger.error("Stream stopped with error: \(error.localizedDescription)") } } I am getting error Value of type 'SCRecordingOutput' has no member 'delegate' Even though I am targeting macOs 15+ ( macOs 26 actually ) and macOs only. What is the best way to achieving the desired result? Is there any other / better way to do it?
Replies
1
Boosts
0
Views
621
Activity
Oct ’25
NSScrollView only scrolls vertically for NSTableView after window resize
Hi everyone, I’m looking for help with an issue where using insertRows to add a row to an NSTableView requires resizing the window before I can scroll to the newly added rows that extend beyond the visible area of the NSScrollView. import Cocoa class ViewController: NSViewController { var data = Constants.movies // Table components var titleField = NSTextField() var directorField = NSTextField() var releaseYearField = NSTextField() var addMovieButton = NSButton(title: "Add Movie", image: NSImage(systemSymbolName: "plus", accessibilityDescription: "")!, target: nil, action: #selector(addMovie)) var table = NSTableView() var titleColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.titleColumnId)) var directorColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.directorColumnId)) var releaseYearColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.releaseColumnId)) // Scroll view let scrollView = NSScrollView() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. view.wantsLayer = true view.layer?.backgroundColor = NSColor.black.cgColor configure() } private func configure() { titleField.translatesAutoresizingMaskIntoConstraints = false directorField.translatesAutoresizingMaskIntoConstraints = false releaseYearField.translatesAutoresizingMaskIntoConstraints = false addMovieButton.translatesAutoresizingMaskIntoConstraints = false scrollView.translatesAutoresizingMaskIntoConstraints = false table.translatesAutoresizingMaskIntoConstraints = false titleField.placeholderString = "Movie Title" directorField.placeholderString = "Name of Director" releaseYearField.placeholderString = "Year Released" // Configure table table.addTableColumn(titleColumn) table.addTableColumn(directorColumn) table.addTableColumn(releaseYearColumn) titleColumn.title = "Movie Title" directorColumn.title = "Director" releaseYearColumn.title = "Year Released" table.delegate = self table.dataSource = self table.focusRingType = .none // Configure scroll view scrollView.documentView = table scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = false scrollView.autohidesScrollers = true // Add views to the hierarchy view.addSubview(titleField) view.addSubview(directorField) view.addSubview(releaseYearField) view.addSubview(addMovieButton) view.addSubview(scrollView) // view.addSubview(table) NSLayoutConstraint.activate([ titleField.widthAnchor.constraint(equalToConstant: 150), directorField.widthAnchor.constraint(equalToConstant: 150), releaseYearField.widthAnchor.constraint(equalToConstant: 150), addMovieButton.widthAnchor.constraint(equalToConstant: 100), titleField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), directorField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), releaseYearField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), addMovieButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), directorField.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant: -10), releaseYearField.leadingAnchor.constraint(equalTo: view.centerXAnchor, constant: 10), titleField.trailingAnchor.constraint(equalTo: directorField.leadingAnchor, constant: -20), addMovieButton.leadingAnchor.constraint(equalTo: releaseYearField.trailingAnchor, constant: 20), scrollView.topAnchor.constraint(equalTo: titleField.bottomAnchor, constant: 20), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20), // table.widthAnchor.constraint(equalTo: scrollView.contentView.widthAnchor), // table.heightAnchor.constraint(equalTo: scrollView.contentView.heightAnchor) ]) } @objc private func addMovie() { let title = titleField.stringValue let director = directorField.stringValue guard let year = Int(releaseYearField.stringValue) else { return } let movie = Movie(title: title, director: director, releaseYear: year) data.append(movie) // Approach 1 // table.reloadData() // Approach 2 let newRow = data.count - 1 table.insertRows(at: IndexSet(integer: newRow), withAnimation: .slideDown) } Using table.reloadData works fine and I can scroll to the new rows as I add them, but it doesn't have the smooth animation I want to achieve. What is the best practice and correct way for using table.insertRows to avoid this issue? Note: I am using programmatic constraints only.
Replies
1
Boosts
0
Views
675
Activity
Oct ’25
SwiftUI buttons behind NSToolbarView are not clickable on macOS 26 beta
Overview Starting with macOS 26 beta 1, a new NSGlassContainerView is added inside NSToolbarView. This view intercepts mouse events, so any SwiftUI Button (or other interactive view) overlaid on the title‑bar / toolbar area no longer receives clicks. (The same code works fine on macOS 15 and earlier.) Filed as FB18201935 via Feedback Assistant. Reproduction (minimal project) macOS 15 or earlier → button is clickable macOS 26 beta → button cannot be clicked (no highlight, no action call) @main struct Test_macOS26App: App { init() { // Uncomment to work around the issue (see next section) // enableToolbarClickThrough() } var body: some Scene { WindowGroup { ContentView() } .windowStyle(.hiddenTitleBar) // ⭐️ hide the title bar } } struct ContentView: View { var body: some View { NavigationSplitView { List { Text("sidebar") } } detail: { HSplitView { listWithOverlay listWithOverlay } } } private var listWithOverlay: some View { List(0..<30) { Text("item: \($0)") } .overlay(alignment: .topTrailing) { // ⭐️ overlay in the toolbar area Button("test") { print("test") } .glassEffect() .ignoresSafeArea() } } } Investigation In Xcode View Hierarchy Debugger, a layer chain NSToolbarView > NSGlassContainerView sits in front of the button. -[NSView hitTest:] on NSGlassContainerView returns itself, so the event never reaches the SwiftUI layer. Swizzling hitTest: to return nil when the result is the view itself makes the click go through: func enableToolbarClickThrough() { guard let cls = NSClassFromString("NSGlassContainerView"), let m = class_getInstanceMethod(cls, #selector(NSView.hitTest(_:))) else { return } typealias Fn = @convention(c)(AnyObject, Selector, NSPoint) -> Unmanaged<NSView>? let origIMP = unsafeBitCast(method_getImplementation(m), to: Fn.self) let block: @convention(block)(AnyObject, NSPoint) -> NSView? = { obj, pt in guard let v = origIMP(obj, #selector(NSView.hitTest(_:)), pt)?.takeUnretainedValue() else { return nil } return v === (obj as AnyObject) ? nil : v // ★ make the container transparent } method_setImplementation(m, imp_implementationWithBlock(block)) } Questions / Call for Feedback Is this an intentional behavioral change? If so, what is the recommended public API or pattern for allowing clicks to reach views overlaid behind the toolbar? Any additional data points or confirmations are welcome—please reply if you can reproduce the issue or know of an official workaround. Thanks in advance!
Replies
3
Boosts
0
Views
699
Activity
Oct ’25
What is the standard process of subclassing NSTextLocation?
Cannot find any guidance in the forums and Developer Doc, the WWDC session Meet TextKit2 says this protocol is served for any location type espacially useful when the underlying doc model is not linear. But when I try to subclass the NSTextLocation with my own type to define a more structured location rather than a linear one, also with my own NSTextContentManager subclass implementation, I keep receiving the system internal Location model like NSCountableTextLocation compare to my location which cause the app to crash. -[NSCountableTextLocation compare:] receiving unmatching type <MarkdownTK2.ChildIndexPathLocation: 0x9b2402aa0> In my own NSTextContentManager subclass: public override func offset( from: any NSTextLocation, to: any NSTextLocation ) -> Int { this method will also both receive my own location and some times receiving the system defined location that I can not calculate the offset then just return zero. The doc only says If you provide your own implementation of the NSTextLocation protocol to manage locations in your content, subclass NSTextContentManager and implement your own storage object to support those locations. OS Development environment: Xcode 26.0, macOS 26.0 Run-time configuration: macOS 26.0
Replies
3
Boosts
0
Views
729
Activity
Oct ’25
Xcode 26 Compiler Critical Issues?
Hello everyone, Since I installed Xcode 26, I've been encountering issues I've never seen before. I have Mac OS applications written in Objective-C, some released as far back as 14 years ago. When compiling them with Xcode 26, I experience efficiency issues related to thread management and interface updates. There are rendering problems with a simple NSTextView created through Interface Builder. The issue is not easily reproducible as it occurs randomly on some machines, regardless of their architecture or macOS version. The main thread freezes, and generally after 15-30 seconds, it unfreezes, loading the interface and text. The length of the text is irrelevant to the issue, and no crashes occur. I spent ten days trying to optimize the code and change the loading order within the class, but the problem persists. However, if I compile the application with Xcode 16.4, everything works like a charm. I also tried using the macOS 15.5 SDK to compile with Xcode 26, but it doesn’t resolve any issues. Additionally, I tried changing the compiler optimization level, but it didn’t solve the problem. This leads me to believe it’s an issue with the Xcode 26 compiler. If it were a code issue, it would be easily reproducible and would also occur when compiling with 16.4. The Xcode 26.1 Beta doesn’t resolve the issue. Can anyone tell me if I need to change something related to the compiler? Are you aware of any issues like this? Thank you, Luca
Replies
0
Boosts
1
Views
628
Activity
Oct ’25
XPC: too many nested collections when explicitly decoding a single collection on macOS 12.7 (not on macOS Tahoe)
I have a custom object which gets passed back to the main app from XPC. I whitelist it like so: NSSet *expectedClass = [NSSet setWithObjects:[NSArray class], [MyCustomClass class], nil]; [interface setClasses:expectedClass forSelector:@selector(myMethodNameHere:withCompletion:) argumentIndex:0 ofReply:YES]; Now my custom class conforms to NSSecureCoding. It does have an array property of another custom class. @property (nonatomic,readonly) NSArray *arraypropertyOfOtherClass; Which is decoded in -initWithCoder: using: -decodeArrayOfObjectsOfClasses:forKey: Now on macOS Tahoe this is all walking fine. But I just tested on macOS Monterey and I get the following error: Exception: decodeObjectForKey: too many nested collections when explicitly decoding a single collection. How should I handle this for earlier versions of macOS?
Replies
2
Boosts
0
Views
625
Activity
Oct ’25
Is it possible to use UITextView in #TextKit2 with a subclass of NSTextContentManager without using NSTextStorage as backing store?
When I tried this, the app crashed immediately with a requirement to use NSTextContentStorage subclass
Replies
4
Boosts
0
Views
2.2k
Activity
Oct ’25
How to bind AppKit window to Observable viewmodel using SwiftUI app life cycle
Hey everyone. I have a macOS app written in SwiftUI. I have multiple SwiftUI Scenes and Views, but needed to write one specific window in AppKit (an NSPanel, to be specific). The problem I'm facing is- I'm not sure how to incorporate this NSPanel with the rest of my SwiftUI/Observable code. I'm relying on the SwiftUI app cycle. For example, I have a boolean in my view model (observation tracked). I'd like to use this boolean to hide/unhide my NSPanel. Any way to cleanly hook into the viewmodel, or onto some specific observable variables would be very very helpful. Thank you everyone.
Replies
1
Boosts
0
Views
330
Activity
Oct ’25
[NSEvent charactersByApplyingModifiers:] not matching NSEvent.characters/charactersIgnoringModifiers
To my surprise [NSEvent charactersByApplyingModifiers:] does not always produce the same NSString result as the originating NSEvent reflects through characters/charactersIgnoringModifiers, even if passing on the event's own modifierFlags. For example, when pressing the 'end' key, both characters and charactersIgnoringModifiers return 0x000000000000f72b, which matches the value of NSEndFunctionKey. But calling [NSEvent charactersByApplyingModifiers:] passing in NSEvent.modifierFlags produces 0x0000000000000004, which matches the value of kEndCharCode. (lldb) po [[((NSApplication*)NSApp).currentEvent characters] characterAtIndex:0] 0x000000000000f72b (lldb) po [[((NSApplication*)NSApp).currentEvent charactersIgnoringModifiers] characterAtIndex:0] 0x000000000000f72b (lldb) po [[((NSApplication*)NSApp).currentEvent charactersByApplyingModifiers:[(NSEvent*)((NSApplication*)NSApp).currentEvent modifierFlags]] characterAtIndex:0] 0x0000000000000004 (The same can be observed with UCKeyTranslate directly, which charactersByApplyingModifiers seems to use internally). I would expect [NSApp.currentEvent charactersByApplyingModifiers:NSApp.currentEvent.modifierFlags] to match either NSApp.currentEvent.characters or NSApp.currentEvent.charactersIgnoringModifiers. Is there a logic behind this perceived discrepancy that I'm missing? Should I always prefer the content of NSEvent.characters/charactersIgnoringModifiers in this case if the modifier flags I'm applying match those of the event itself? Thanks for any insights! (Also reported as FB20591338)
Topic: UI Frameworks SubTopic: AppKit Tags:
Replies
3
Boosts
0
Views
276
Activity
Oct ’25
NSOutlineView (Multiple Selection): How to prevent Child Row Deselection on Collapse
I’ve enabled multiple selection in NSOutlineView. When I collapse a parent item, all of its selected child rows get deselected automatically. Is there a way to prevent this deselection so that selections remain intact when the parent is collapsed and restored when it’s expanded again?
Topic: UI Frameworks SubTopic: AppKit Tags:
Replies
1
Boosts
0
Views
246
Activity
Oct ’25
Resize Window Form After Loading
I am trying to resize a Window Form after it loads and have done quite a bit of searching for code to do it. Here is one code snippet that works to size the form during the design phase. self.view.window?.contentMinSize = CGSize(width: 1100, height: 310) I have tried code like below to increase the window size after the Form loads if let myWindow = self.view.window ?? NSApplication.shared.mainWindow { // Increase window size and position after it loads let newRect = NSRect(x: 100, y: 100, width: 1400, height: 900) } It seems that this code not only changes the Form size after loading, but also changes the size of the Form in Main.swift, which is something I don't want. I read elsewhere that I had to disable constraints to resize the Form, so I tried code below. let tableView = NSTableView() tableView.translatesAutoresizingMaskIntoConstraints = false let newRect = NSRect(x: 100, y: 0, width: 1100, height: 600) myWindow?.setFrame(newRect, display: true) That code did not seem to do anything as well. Also, the Form displays in the lower left of the screen. Note that main reason I want to resize the Form after loading is to keep it smaller during design development. The same goes for the NSTableView, which I have not gotten to yet.
Replies
0
Boosts
0
Views
332
Activity
Oct ’25
NSHostingSceneRepresentation doesn't show Window(_:id:) and UtilityWindow(_:id:) with .openWIndow(id:)
NSHostingSceneRepresentation, introduced in macOS 26, allows calling SwiftUI’s windows and other elements set in a Scene from AppKit. However, while Settings and WindowGroup set in the Scene can be invoked as expected using environment.openSettings() and environment.openWindow(id:) respectively, calling Window or WindowUtility doesn’t work. That is, the app just fails to open the desired window with the provided ID, and no error message or other feedback/crash/freeze appears. I expect that executing the openUtilityWindow(_:)action in the following code will display the UtilityWindow set in the scene. However, the window does not actually open. @main final class AppDelegate: NSObject, NSApplicationDelegate { private let scene = NSHostingSceneRepresentation { UtilityWindow("Utility Window", id: "UtilityWindow") { Text("Utility Window") .scenePadding() } } func applicationWillFinishLaunching(_ notification: Notification) { NSApp.addSceneRepresentation(self.scene) } @IBAction func openUtilityWindow(_ sender: Any?) { self.scene.environment.openWindow(id: "UtilityWindow") } } Is there something wrong with my implementation and expectation? Or is this a bug in NSHostingSceneRepresentation? Just in case, I’ve already filed this issue withFeedback Assistant: FB20310722 This feedback also includes a sample project reproducing this issue.
Replies
1
Boosts
1
Views
482
Activity
Oct ’25
Why does AppStore.requestReview(in:) require NSViewController Parameter?
Looking to update one of my apps that uses SKStoreReviewController +requestReview (deprecated) to AppStore.requestReview(in:) umm...I have a few of questions... Why is an NSViewController parameter required? It's really not so uncommon for an AppKit app to just use NSWindowController with a window that does not use NSViewController... It should be possible to present the review request in a standalone alert (attached to a window is preferred IMO but it still should be possible to ask in separate window). 3)...why Swift..(err nevermind) Ideally: AppStore requestReview should take a NSWindow parameter but that parameter should be optional. If nil the request should be presented in a standalone window (like an alert). If non nil..present as a sheet on the window. Why a view controller? Maybe I'm missing something.
Replies
2
Boosts
0
Views
344
Activity
Oct ’25
Grammar checking is never requested
I have prepared a NSSpellServer spelling and grammar checker for Slovenian proofing in macOS. My proofing service gets used when I explicitly set keyboard spelling language to "Slovenian (Besana)" (my proofing service). However, no matter how I set the Check Grammar With Spelling option or Check Grammar checkbox in the TextEdit.app or Mail.app, my proofing service does not get any request for grammar checking. I am supporting checkString call for Unified checking and checkingTypes never contains NSTextCheckingTypeGrammar flag. When using legacy API before Unified checking support, the checkGrammarInString is never called either. If I do the grammar regardless the checkingTypes parameter, the app shows grammar mistakes correctly. But that is bad UX. Need to follow user demand for with grammar or without grammar. I don't know what am I doing wrong? On my home iMac v11 it actually works. No idea what I did there to make it work. Just worked. On my working Mac Mini v13 it won't check grammar. On another MacBook Pro v15, it won't check grammar either. Apps do check spelling with my proofing service. But not grammar. Same apps do grammar checking with stock AppleSpelling.service just fine. I have checked my Info.plist, using Hardened Runtime, have empty Entitlements, to no avail. Was there some new grammar API introduced after macOS v11 Big Sur, I should implement? Is there some specific Entitlement, signature, notarization I should perform to get going? Some documentation I am missing?
Replies
2
Boosts
0
Views
417
Activity
Oct ’25
ProgressView Tint doesn't work on macOS
I seem to be unable to affect the color of a linear ProgressView() on macOS and need to know if this is a feature or a bug. I have the following: ProgressView(value: someProgress).tint(.green) This works fine in iOS, the linear ProgressView changes to the desired color. On macOS the ProgressView stays the color of the system accent. .progressViewStyle(LinearProgressViewStyle(tint: .blue)) Is available, but depreciated, or being depreciated. I have also tried: .tint(.red) .accentColor(.green) While I can understand the platform specific differences, the context that I'm using really would benefit from keeping the UI elements colored consistent with the app, rather than the OS. Also I can do it in iOS, why not macOS? Both dev and test machines are running latest updates (Xcode 26.0.1/macOS 26.0.1 and iOS 26.0.1/macOS26.0.1)
Replies
3
Boosts
0
Views
288
Activity
Oct ’25
NSDocument doesn't autosave last changes
I had noticed an unsettling behaviour about NSDocument some years ago and created FB7392851, but the feedback didn't go forward, so I just updated it and hopefully here or there someone can explain what's going on. When running a simple document-based app with a text view, what I type before closing the app may be discarded without notice. To reproduce it, you can use the code below, then: Type "asdf" in the text view. Wait until the Xcode console logs "saving". You can trigger it by switching to another app and back again. Type something else in the text view, such as "asdf" on a new line. Quit the app. Relaunch the app. The second line has been discarded. Am I doing something wrong or is this a bug? Is there a workaround? class ViewController: NSViewController { @IBOutlet var textView: NSTextView! } class Document: NSDocument { private(set) var text = "" override class var autosavesInPlace: Bool { return true } override func makeWindowControllers() { let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil) let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! NSWindowController (windowController.contentViewController as? ViewController)?.textView.string = text self.addWindowController(windowController) } override func data(ofType typeName: String) throws -> Data { Swift.print("saving") text = (windowControllers.first?.contentViewController as? ViewController)?.textView.string ?? "" return Data(text.utf8) } override func read(from data: Data, ofType typeName: String) throws { text = String(decoding: data, as: UTF8.self) (windowControllers.first?.contentViewController as? ViewController)?.textView.string = text } }
Topic: UI Frameworks SubTopic: AppKit Tags:
Replies
17
Boosts
0
Views
808
Activity
Oct ’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:
Replies
2
Boosts
0
Views
480
Activity
Sep ’25