Post

Replies

Boosts

Views

Activity

How do you allow an XPC service to create a new file based on an NSURL that the user selected from an NSSavePanel?
How do you send an NSURL representing a new file, as returned from an NSSavePanel, to an XPC service such that the service is granted permission to create the file? I can successfully pass an NSURL to the XPC process if the NSURL represents an existing file. This is documented in Apple's Documentation: Share file access between processes with URL bookmarks This involves creating bookmark date while passing 0 in as the options. However, if you try to create bookmark data for an NSURL that represents a file that is not yet created, you do not get any bookmark data back and an error is returned instead: Error Domain=NSCocoaErrorDomain Code=260 "The file couldn’t be opened because it doesn’t exist." Simply passing the file path to the XPC process, by way of: xpc_dictionary_set_string(message, "file_path", url.fileSystemRepresentation); Does not grant the XPC create/write permissions. Is there an API or trick I'm missing? Note that the user should be allowed to save and create new files anywhere of their choosing, thus restricting URLs to only those within a group or container shared between the app and service isn't really viable. Using the latest of everything on macOS with the xpc_session API...
1
0
961
Jun ’24
Possibly Incorrect Statement in AppKit Release Notes for macOS 14.
While trying to debug some weird drawing issues under macOS 14, I remembered that there was a comment in the AppKit Release notes related to drawing and NSView.clipsToBounds. AppKit Release Notes for macOS 14 Under the section titled NSView, the following statement is made: For applications linked against the macOS 14 SDK, the default value of this property is true. Apps linked against older SDKs default to false. Some classes, like NSClipView, continue to default to true. Is this statement possibly backwards? From what I can tell, under macOS 14 NSView.clipsToBounds now defaults to false. I came across this while trying to debug an issue where views that override drawRect with the intent of calling NSFillRect(self.bounds) with a solid color are, sometimes, briefly flickering because self.bounds is NSZeroRect, even though self.frame is not (nor is the dirtyRect). This seems to be happening when views are added as subviews to a parent view. The subviews, which override drawRect, periodically "miss" a repaint and thus flicker. This seems to happen when views are frequently added or removed, like what happens in a scrolling view that is "recycling" views as they go offscreen. Views that scroll into the viewport are added as subviews and, sometimes, briefly flicker. Replacing calls to drawRect with wantsUpdateLayer and updateLayer eliminates the flickering, which makes me think something is going astray in drawRect and the various rects you can use. This is with Xcode 15.4, linking against macOS 14.5 and running on macOS 14.6.1
2
0
711
Oct ’24
Should you access @State properties from an NSViewController (AppKit / SwiftUI Integration)?
I'm currently working on a project to integrate some SwiftUI components into an existing AppKit application. The application makes extensive use of NSViewControllers. I can easily bridge between AppKit and SwiftUI using a view model that conforms to ObservableObject and is shared between the NSViewController and the SwiftUI View. But it's kind of tedious creating a view model for every view. Is it "safe" and "acceptable" for the NSViewController to "hold on" to the SwiftUI View that it creates and then access its @State or @StateObject properties? The lifecycle of DetailsView, a SwiftUI View, isn't clear to me when viewed through the lens of an NSViewController. Consider the following: import AppKit import SwiftUI struct DetailsView: View { @State var details: String = "" var body: some View { Text(details) } } final class ViewController: NSViewController { private let detailsView: DetailsView init() { self.detailsView = DetailsView() super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { view.addSubview(NSHostingView(rootView: detailsView)) } func updateDetails(_ details: String) { // Is this 'safe' and 'acceptable'? self.detailsView.details = details } } Is the view controller guaranteed to always be updating the correct @State property or is there a chance that the view controller's reference to it somehow becomes stale because of a SwiftUI update?
2
0
99
Apr ’25
Can SwiftUI on macOS create an NSComboButton?
Without resorting to NSViewRepresentable, is there a view or view modifier in SwiftUI that can create an NSComboButton on macOS? NSComboButton was introduced in macOS 13 and is (relatively) new to AppKit: Apple Developer - NSComboButton I only require support on macOS for this control. Note that this is not to be confused with NSComboBox, which is a completely different control.
1
0
108
Apr ’25
How to create a momentary segmented control in SwiftUI for macOS?
In AppKit, NSSegmentedControl has various styles defined by NSSegmentStyle and various tracking modes defined by NSSegmentSwitchTracking. How can we set these properties in SwiftUI? I'm currently using a Picker with the view modifier .pickerStyle(.segmented) applied but this seems to produce a segmented control with tracking set to "select one". In particular I'm looking for momentary tracking so that I can create navigation-style buttons for backward/forward navigation. Under AppKit, the canonical way to do this is an NSSegmentedControl of style separated and tracking momentary. Is that possible under SwiftUI for macOS? (Using the latest versions of everything.)
1
0
109
Apr ’25
Does MKLookAroundViewController work on macOS?
Trying to incorporate a LookAroundView into my macOS application but unable to make the LookAroundView interactive at all. I can get it to display a static image, but there's no interactivity at all and no controls visible. This is using the SwiftUI LookAroundPreview view as well as trying to wrap MKLookAroundViewController inside an NSViewRepresentable. The navigation properties are set to true but that doesn't seem to make a difference. Would love to incorporate this feature but without interactivity its value is limited. macOS 15.4.1 (24E263), Xcode Version 16.3 (16E140)
1
0
100
Apr ’25
How to correctly set a Picker's selection and contents in SwiftUI for macOS?
How do you atomically set a Picker's selection and contents on macOS such that you don't end up in a situation where the selection is not present within the Picker's content? I presume Picker on macOS is implemented as an NSPopUpButton and an NSPopUpButton doesn't really like the concept of "no selection". SwiftUI, when presented with that, outputs: Picker: the selection "nil" is invalid and does not have an associated tag, this will give undefined results. Consider the following pseudo code: struct ParentView: View { @State private var items: [Item] var body: some View { ChildView(items: items) } } struct ChildView: View { let items: [Item] @State private var selectedItem: Item? var body: some View { Picker("", selection: $selectedItem) { ForEach(items) { item in Text(item.name).tag(item) } } } } When items gets passed down from ParentView to the ChildView, it's entirely possible that the current value in selectedItem represents an Item that is not longer in the items[] array. You can "catch" that by using .onAppear, .task, .onChange and maybe some other modifiers, but not until after at least one render pass has happened and an error has likely been reported because selectedItem is nil or it's not represented in the items[] array. Because selectedItem is private state, a value can't easily be passed down from the parent view, though even if it could that just kind of moves the problem one level higher up. What is the correct way to handle this type of data flow in SwiftUI for macOS?
1
0
167
May ’25
How do you restore a Sheet's window frame in SwiftUI for macOS
On macOS, it's not uncommon to present windows as sheets that can be resized. By setting the NSWindow's various frame auto save properties, you can restore the size of the sheet the next time it is presented. When presenting a Sheet from within SwiftUI using the .sheet view modifier, how can I preserve and restore the sheet's frame size? The closest I've been able to come is to put the SwiftUI view into a custom NSHostingController and then into an NSViewControllerRepresentable and then override viewWillAppear and look for self.view.window, which is all little awkward. Is there a more idiomatic way to achieve this in "pure" SwiftUI?
2
0
100
May ’25
How to effectively use task(id:) when multiple properties are involved?
While adopting SwiftUI (and Swift Concurrency) into a macOS/AppKit application, I'm making extensive use of the .task(id:) view modifier. In general, this is working better than expected however I'm curious if there are design patterns I can better leverage when the number of properties that need to be "monitored" grows. Consider the following pseudo-view whereby I want to call updateFilters whenever one of three separate strings is changed. struct FiltersView: View { @State var argument1: String @State var argument2: String @State var argument3: String var body: some View { TextField($argument1) TextField($argument2) TextField($argument3) }.task(id: argument1) { await updateFilters() }.task(id: argument2) { await updateFilters() }.task(id: argument3) { await updateFilters() } } Is there a better way to handle this? The best I've come up with is to nest the properties inside struct. While that works, I now find myself creating these "dummy types" in a bunch of views whenever two or more properties need to trigger an update. ex: struct FiltersView: View { struct Components: Equatable { var argument1: String var argument2: String var argument3: String } @State var components: Components var body: some View { // TextField's with bindings to $components... }.task(id: components) { await updateFilters() } } Curious if there are any cleaner ways to accomplish this because this gets a bit annoying over a lot of views and gets cumbersome when some values are passed down to child views. It also adds an entire layer of indirection who's only purpose is to trigger task(id:).
2
0
127
May ’25
On macOS, how do you place a toolbar item on the trailing edge of the window's toolbar when an Inspector view is open?
Using SwiftUI on macOS, how can I add a toolbar item on the right-most (trailing) edge of the window's toolbar when an Inspector is used? At the moment, the toolbar items are all left-of (leading) the split view tracking separator. I want the inspector toolbar item to be placed similar to where Xcode's Inspector toolbar item is placed: always as far right (trailing) as possible. NavigationSplitView { // ... snip } detail: { // ... snip } .inspector(isPresented: $isInspectorPresented) { InspectorContentView() } .toolbar { // What is the correct placement value here? ToolbarItem(placement: .primaryAction) { Button { isInspectorPresented.toggle() } label: { Label("Toggle Inspector", systemImage: "sidebar.trailing") } } } See the attached screenshot. When the InspectorView is toggled open, the toolbar item tracks leading the split view tracking separator, which is not consistent with how Xcode works.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
4
0
108
Aug ’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.
1
0
129
Nov ’25
Clarification on SwiftUI Environment Write Performance
I'm looking for clarification on a SwiftUI performance point mentioned in the recent Optimize your app's speed and efficiency | Meet with Apple video. (YouTube link not allowed, but the video is available on the Apple Developer channel.) At the 1:48:50 mark, the presenter says: Writing a value to the Environment doesn't only affect the views that read the key you're updating. It updates any view that reads from any Environment key. [abbreviated quote] That statement seems like a big deal if your app relies heavily on Environment values. Context I'm building a macOS application with a traditional three-panel layout. At any given time, there are many views on screen, plus others that exist in the hierarchy but are currently hidden (for example, views inside tab views or collapsed splitters). Nearly every major view reads something from the environment—often an @Observable object that acts as a service or provider. However, there are a few relatively small values that are written to the environment frequently, such as: The selected tab index The currently selected object on a canvas The Question Based on the presenter's statement, I’m wondering: Does writing any value to the environment really cause all views in the entire SwiftUI view hierarchy that read any environment key to have their body re-evaluated? Do environment writes only affect child views, or do they propagate through the entire SwiftUI hierarchy? Example: View A └─ View B ├─ View C └─ View D If View B updates an environment value, does that affect only C and D, or does it also trigger updates in A and B (assuming each view has at least one @Environment property)? Possible Alternative If all views are indeed invalidated by environment writes, would it be more efficient to “wrap” frequently-changing values inside an @Observable object instead of updating the environment directly? // Pseudocode @Observable final class SelectedTab { var index: Int } ContentView() .environment(\.selectedTab, selectedTab) struct TabView: View { @Environment(\.selectedTab) private var selectedTab var body: some View { Button("Action") { // Would this avoid invalidating all views using the environment? selectedTab.index = 1 } } } Summary From what I understand, it sounds like the environment should primarily be used for stable, long-lived objects—not for rapidly changing values—since writes might cause far more view invalidations than most developers realize. Is that an accurate interpretation? Follow-Up In Xcode 26 / Instruments, is there a way to monitor writes to @Environment?
4
0
1.1k
Nov ’25
Re-Visiting NSViewController.loadView's behaviour in 2024 and under macOS 15...
This is a post down memory lane for you AppKit developers and Apple engineers... TL;DR: When did the default implementation of NSViewController.loadView start making an NSView when there's no matching nib file? (I'm sure that used to return nil at some point way back when...) If you override NSViewController.loadView and call [super loadView] to have that default NSView created, is it safe to then call self.view within loadView? I'm refactoring some old Objective-C code that makes extensive use of NSViewController without any use of nibs. It overrides loadView, instantiates all properties that are views, then assigns a view to the view controller's view property. This seems inline with the documentation and related commentary in the header. I also (vaguely) recall this being a necessary pattern when not using nibs: @interface MyViewController: NSViewController // No nibs // No nibName @end @implementation MyViewController - (void)loadView { NSView *hostView = [[NSView alloc] initWithFrame:NSZeroRect]; self.button = [NSButton alloc...]; self.slider = [NSSlider alloc...]; [hostView addSubview:self.button]; [hostView addSubview:self.slider]; self.view = hostView; } @end While refactoring, I was surprised to find that if you don't override loadView and do all of the setup in viewDidLoad instead, then self.view on a view controller is non-nil, even though there was no nib file that could have provided the view. Clearly NSViewController has realized that: There's no nib file that matches nibName. loadView is not overridden. Created an empty NSView and assigned it to self.view anyways. Has this always been the behaviour or did it change at some point? I could have sworn that if there as no matching nib file and you didn't override loadView, then self.view would be nil. I realize some of this behaviour changed in 10.10, as noted in the header, but there's no mention of a default NSView being created. Because there are some warnings in the header and documentation around being careful when overriding methods related to view loading, I'm curious if the following pattern is considered "safe" in macOS 15: - (void)loadView { // Have NSViewController create a default view. [super loadView]; self.button = [NSButton...]; self.slider = [NSSlider...]; // Is it safe to call self.view within this method? [self.view addSubview:self.button]; [self.view addSubview:self.slider]; } Finally, if I can rely on NSViewController always creating an NSView for me, even when a nib is not present, then is there any recommendation on whether one should continue using loadView or instead move code the above into viewDidLoad? - (void)viewDidLoad { self.button = [NSButton...]; self.slider = [NSSlider...]; // Since self.view always seems to be non-nil, then what // does loadView offer over just using viewDidLoad? [self.view addSubview:self.button]; [self.view addSubview:self.slider]; } This application will have macOS 15 as a minimum requirement.
0
1
479
Nov ’24