Post

Replies

Boosts

Views

Activity

How do you set the color of an NSImage symbol when used as the contents of a CALayer?
I'm trying to use an NSImage that represents an SF Symbol as the contents of a CALayer. NSImage has an API for this in the form of [NSImage layerContentsForContentsScale:]. On the NSImage documentation page, there's even a few paragraph at the top dedicated to using this very method. But how do you set the color you want the image to render as if the image is an SF Symbol? NSImageView has .contentTintColor which works great, but CALayer has no such property. final class SymbolLayer: CALayer { func display() { // Just an example... let image = NSImage(systemSymbolName: "paperclip", accessibilityDescription: nil)! let actualScaleFactor = image.recommendedLayerContentsScale(contentsScale) // This obviously produces a black image because there's no color or tint information anywhere.     contents = image.layerContents(forContentsScale: actualScaleFactor) } } Is there a way you can configure the CALayer or the NSImage itself to have some sort of color information when it generates the layer contents? I've attempted to play around with the SymbolConfiguration coolers but without any success. (Even when wrapped inside NSAppearance.performAsCurrentDrawingAppearance.) The best I can come up with is to use CALayer.draw(in:) and then use the old NSImage.cgImage(forProposedRect:...) API. I can then set the fill color on the CGContext and go from there. Is there a more efficient way? override func draw(in context: CGContext) { let image = NSImage(systemSymbolName: "paperclip", accessibilityDescription: nil)!   var rect = bounds image.size = bounds.size let cgImage = image.cgImage( forProposedRect: &rect, context: nil, hints: [.ctm: AffineTransform(scale: contentsScale)] )! NSApp.effectiveAppearance.performAsCurrentDrawingAppearance { // Draw using an Appearance-sensitive color.     context.clip(to: bounds, mask: cgImage)     context.setFillColor(NSColor.labelColor.cgColor)     context.fill(bounds)   } } This is for macOS 12+.
Topic: UI Frameworks SubTopic: AppKit Tags:
0
0
1.7k
Sep ’21
How do you encrypt an AppleArchive with a "human" password?
In WWDC21 session 10233: Bring Encrypted Archives and Performance Improvements to Your App with Accelerate, there is an example of encrypting a directory using the AppleArchive framework. There is also accompanying sample code. However, that sample code uses a SymmetricKey and the hkdf_sha256_aesctr_hmac__symmetric__none profile. The key is set by calling context.setSymmetricKey(encryptionKey). How can you perform the same operation of encrypting a directory using AppleArchive but with a "human" password? (i.e.: A password provided by the user from a prompt?) Simply changing the profile to hkdf_sha256_aesctr_hmac__scrypt__none and then calling `context.setPassword("MyPassword") producing the following output "Error setting password (invalidValue)." I also tried using the command line aea application, but received the output Password is too short. Prompt: > aea encrypt -v -password-value "password" -profile 5 -i MyDirectory -o MyDirectory.aea Operation: encrypt input: FOO output: FOO.aea profile: hkdf_sha256_aesctr_hmac__scrypt__none worker threads: 10 auth data (raw): 0 B compression: lzfse 1 MB Error 0xb9075800 Password is too short Main key derivation failed (-2) Main key derivation Invalid encryption parameters Finally, in the file AEAContext.h, there is a comment associated with the method AEAContextSetPassword() that states: Set context password Stores a copy of password in context. Required to encrypt / decrypt a stream when encryption mode is SCRYPT. An internal size range is enforced for the password. The caller is expected to enforce password strength policies. @param context target object @param password password (raw data) @param password_size password size (bytes) @return 0 on success, a negative error code on failure I cannot find any other documentation that states what the password policy. And if there is a password policy for AppleEncryptedArchives, does that mean AEA is not a good fit for encrypting personal directories where the user just wants to use "any old password", regardless of the password's strength?
0
0
1.1k
Apr ’23
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
The @Environment(\.dismiss) value in SwiftUI for macOS does not dismiss a sheet presented by an NSWindowController.
I'm wondering what the correct, or recommended, way is to dismiss a SwiftUI that is being presented as a sheet hosted by an NSHostingController. The usual technique of invoking @Environment(\.dismiss) does not appear to work. Consider the code below. An NSWindowController is attempting to display a SwiftUI SettingsView as a sheet. The sheet is correctly presented, but the SettingsView is unable to dismiss itself. I am able to make it work by passing a closure into SettingsView that calls back to the NSWindowController but it's rather convoluted because SettingsView doesn't know the view controller that's hosting it until after SettingsView has been created, which means "finding" that view controller in the window controller to dismiss is more involved than it should be. Is there a better strategy to leverage here? final class MyViewController: NSViewController { @IBAction func buttonClicked(_ sender: NSButton) { if let presenter = window?.contentViewController { presenter.presentAsSheet(NSHostingController(rootView: SettingsView())) } } } struct SettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { VStack { Button("Cancel", role: .cancel) { dismiss() // This call does not dismiss the sheet. } .keyboardShortcut(.cancelAction) } } } Thank you. macOS 15.4.1 (24E263), Xcode 16.3 (16E140)
0
0
81
Apr ’25
Is it reasonable to vend an NSView from a "ViewModel" when using NSViewRepresentable instead of implementing the Coordinator pattern?
I'm currently integrating SwiftUI into an AppKit based application and was curious if the design pattern below was viable or not. In order to "bridge" between AppKit and SwiftUI, most of my SwiftUI "root" views have aViewModel that is accessible to the SwiftUI view via @ObservedObject. When a SwiftUI views need to use NSViewRepresentable I'm finding the use of a ViewModel and a Coordinator to be an unnecessary layer of indirection. In cases where it makes sense, I've just used the ViewModel as the Coordinator and it all appears to be working ok, but I'm curious if this is reasonable design pattern or if I'm overlooking something. Consider the following pseudo code: // 1. A normal @ObservedObject acting as the ViewModel that also owns and manages an NSTableView. @MainActor final class ViewModel: ObservedObject, NSTableView... { let scrollView: NSScrollView let tableView: NSTableView @Published var selectedTitle: String init() { // ViewModel manages tableView as its dataSource and delegate. tableView.dataSource = self tableView.delegate = self } func reload() { tableView.reloadData() } // Update view model properties. // Simpler than passing back up through a Coordinator. func tableViewSelectionDidChange(_ notification: Notification) { selectedTitle = tableView.selectedItem.title } } // 2. A normal SwiftUI view, mostly driven by the ViewModel. struct ContentView: View { @ObservedObject model: ViewModel var body: some View { Text(model.selectedTitle) // No need to pass anything down other than the view model. MyTableView(model: model) Button("Reload") { model.reload() } Button("Delete") { model.deleteRow(...) } } } // 3. A barebones NSViewRepresentable that just vends the required NSView. No other state is required as the ViewModel handles all interactions with the view. struct MyTableView: NSViewRepresentable { // Can this even be an NSView? let model: ViewModel func makeNSView(context: Context) -> some NSView { return model.scrollView } func updateNSView(_ nsView: NSViewType, context: Context) { // Not needed, all updates are driven through the ViewModel. } } From what I can tell, the above is working as expected, but I'm curious if there are some situations where this could "break", particularly around the lifecycle of NSViewRepresentable Would love to know if overall pattern is "ok" from a SwiftUI perspective.
0
0
58
Apr ’25
Can SwiftUI TextFields in a List on macOS be marked as always editable?
In SwiftUI's List, on macOS, if I embed a TextField then the text field is presented as non-editable. If the user clicks on the text and waits a short period of time, the text field will become editable. I'm aware this is generally the correct behaviour for macOS. However, is there a way in SwiftUI to supress this behaviour such that the TextField is always presented as being editable? I want a scrollable, List of editable text fields, much like how a Form is presented. The reason I'm not using a Form is because I want List's support for reordering by drag-and-drop (.onMove). Use Case A view that allows a user to compose a questionnaire. They are able to add and remove questions (rows) and each question is editable. They require drag-and-drop support so that they can reorder the questions.
0
0
119
May ’25
How do you autoscroll a ScrollView during a DragGesture on macOS?
In SwiftUI for macOS, when implementing a DragGesture inside a ScrollVIew, how can I implement auto-scrolling when the mouse is not actively moving? In AppKit, this would normally be done with a periodic event so that auto-scrolling continues to take place even if the user isn't actively moving the mouse. This is essential behaviour when implementing something like a drag-to-select gesture. NSView.autoscroll(with: NSEvent) -> Bool Is there anything in SwiftUI or ScrollView to accomplish this behaviour?
Topic: UI Frameworks SubTopic: SwiftUI Tags:
0
0
150
Aug ’25
How to apply SwiftUI window modifiers when using Xcode's #Preview on a macOS view?
Is there a way to configure the style and toolbar of the macOS window that Xcode uses in #Preview? I am working on a macOS application and want to preview some SwiftUI views within different window styles, toolbar styles and window title/subtitle visibilities. Some of the modifiers to control the look-and-feel of a window are actually Scene Modifiers, not View Modifiers: .windowStyle .windowToolbarLabelStyle .windowToolbarStyle But #Preview does not accept Scenes, so I can't apply these modifiers: // Error, not a view modifier. #Preview { ContentView() .windowStyle(...) } // Error, Window is not supported in #Preview. #Preview { Window("Browser", id: "browser") { ContentView() } } If I give my ContentView a .toolbar(...), Xcode's Preview will correctly show a window with a toolbar, but not necessarily in the style I want. Is there a way to apply the Scene Modifiers to #Preview so that I can see how they affect the window's chrome and toolbar?
Topic: UI Frameworks SubTopic: SwiftUI Tags:
0
0
66
Oct ’25
Correct way to hide sidebar after selection.
In a triple-column split view, it's common to hide the primary view when the user selects an item from a list. In some cases, the supplemental view is also hidden when an item is selected from that list, thus leaving only the detail view visible. What is the correct way to hide the primary view on selection and then to optionally hide the supplemental view on selection using the new NavigationStack? (Notes is a good example of the sidebars hiding after the user selects a folder in the sidebar.)
1
2
1.5k
Jun ’22
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
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
107
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
108
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
98
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
166
May ’25