I have an NSMutableArray defined as a property in my ViewController class:
@interface ViewController ()
@property NSMutableArray *tableCities;
@end
When the "Add" button is clicked, a new city is added:
NSString* filePath = @"/tmp/city_test.jpeg";
NSDictionary *obj = @{@"image": [[NSImage alloc] initByReferencingFile:filePath],
@"name": @"testCity",
@"filePath": filePath};
[_tableCities addObject: obj];
Okay, this is fine, it is adding a new element to this NSMutableArray, now what I want is to somehow bind the "name" field of each city to my NSPopUpButton.
So in storyboard I created an NSArrayController and tried to set its "Model Key Path" to my NSMutableArray as shown below:
Then I tried to bind the NSPopUpButton to the NSArrayController as follows:
but it doesn't work either, a city is added but the NSPopUpButton isn't displaying anything, what gives?
AppKit
RSS for tagConstruct and manage a graphical, event-driven user interface for your macOS app using AppKit.
Posts under AppKit tag
171 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
In genealogy software, I have an NSView that displays a family tree where each person is in a subview. Before Sequoia, the subviews would draw in the order I add them to the parent NSView. For some reason, Sequoia calls drawRect in reverse order.
For example, a tree with cells for son, father, and mother used to be drawn in that order, but Sequoia draws them as mother, father, and son.
For static cell placement it would not matter, but these trees dynamically adjust as users change data or expand and contract branches from the tree. Drawing them in the wrong order messes up all the logic and many trees are corrupted.
Has the new drawing order been implemented for some reason and can it be changed? Is it documented?
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
I want to simulate the pressing of Fn (Globe) + Control + arrow keys combo, but I’m encountering an issue where the Fn modifier seems to be ignored, and the system behaves as if only Control + arrow keys are pressed.
In macOS, the combination of Fn + Right Arrow (key code 124) is treated as End (key code 119), and even that didn’t have expected behavior. Instead of moving the window to the right edge of the screen on Sequoia, it switches to the next space, which is the default behavior for Control + Right Arrow.
Demo:
(I included Fn + Control + C to show that centering the window works for example.)
import SwiftUI
@main
struct LittleKeypressDemo: App {
var body: some Scene {
Window("Keypress Demo", id: "keypress-demo") {
ContentView()
}
.windowStyle(.hiddenTitleBar)
.windowResizability(.contentSize)
.windowBackgroundDragBehavior(.enabled)
}
}
struct ContentView: View {
var body: some View {
VStack(spacing: 20) {
KeyPressButton(icon: "arrowtriangle.right.fill", keyCode: 124)
KeyPressButton(icon: "arrow.down.to.line", keyCode: 119)
KeyPressButton(label: "C", keyCode: 8)
}
.padding()
}
}
struct KeyPressButton: View {
let icon: String?
let label: String?
let keyCode: CGKeyCode
init(icon: String? = nil, label: String? = nil, keyCode: CGKeyCode) {
self.icon = icon
self.label = label
self.keyCode = keyCode
}
var body: some View {
Button(action: { simulateKeyPress(keyCode) }) {
HStack {
Image(systemName: "globe")
Image(systemName: "control")
if let icon = icon {
Image(systemName: icon)
} else if let label = label {
Text(label)
}
}
}
.buttonStyle(.bordered)
.controlSize(.large)
}
}
func simulateKeyPress(_ keyCode: CGKeyCode) {
let fnKey = VirtualKey(keyCode: 63, flags: .maskSecondaryFn)
let controlKey = VirtualKey(keyCode: 59, flags: [.maskControl, .maskSecondaryFn])
let targetKey = VirtualKey(keyCode: keyCode, flags: [.maskControl, .maskSecondaryFn])
[fnKey, controlKey, targetKey].forEach { $0.pressAndRelease() }
}
struct VirtualKey {
let keyCode: CGKeyCode
let flags: CGEventFlags
func pressAndRelease() {
postKeyEvent(keyDown: true)
postKeyEvent(keyDown: false)
}
private func postKeyEvent(keyDown: Bool) {
guard let event = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: keyDown) else { return }
event.flags = flags
event.post(tap: .cghidEventTap)
}
}
Expected behavior:
Simulating the key combo Fn + Control + Right Arrow on macOS Sequoia should move the current window to the right half of the screen, instead of switching to the next desktop space.
Questions:
Is CGEventFlags.maskSecondaryFn enough to simulate the Fn key in combination with Control and the arrow keys? Are there alternative approaches or workarounds to correctly simulate this behavior? What’s the obvious thing I missing?
(Btw., window management is completely irrelevant here. I’m specifically asking about simulating these key presses.)
Any insights or suggestions would be greatly appreciated.
Thank you.
My view controller has this property:
@property NSMutableArray *tableCities;
Whenever I press a button a new city object is added to this array, it consists of a dictionary of NSStrings containing the name and state of the city being added.
Now, I have an NSPopUpButton that I'd like to bind to the city name of all cities in this NSMutableArray, how exactly can I achieve this with the Bindings Inspector?
I'm trying to display my images in a tableView, I'm using NSFIleManager and NSDirectoryEnumerator to get all files in the current folder:
NSString *path = @"/Users/eagle/Documents/avatars";
NSFileManager *fileManager = NSFileManager.defaultManager;
NSDirectoryEnumerator *directoryEnum = [fileManager enumeratorAtPath:path];
NSString *file;
while (file = [directoryEnum nextObject])
{
// ...
}
the problem is that this line
file = [directoryEnum nextObject]
always returns nil, what gives?
I already made sure that this folder has no subfolders and contains only images, so what's the problem here?
Topic:
App & System Services
SubTopic:
General
Tags:
Foundation
AppKit
App Sandbox
Files and Storage
I have created a progress indicator to simulate some progressing download task in the dock icon. However, I can see the progress bar appearing in the dock icon but it is not getting updated when I invoked the updateProgress() method. Ideally it should have updated it, and I m not able to figure out the reason?
I have creating the same NSProgressIndicator on an NSWindow and it works to update the progress bar with the same code. Anything that I m missing to understand here? Below is the code I m using:
class AppDelegate: NSObject, NSApplicationDelegate {
var progressIndicator: NSProgressIndicator!
let dockTile = NSApp.dockTile
func applicationWillFinishLaunching(_ notification: Notification) {
// Step 1: Create a progress bar (NSProgressIndicator)
progressIndicator = NSProgressIndicator(frame: NSRect(x: 10, y: 10, width: 100, height: 20))
progressIndicator.isIndeterminate = false
progressIndicator.minValue = 0.0
progressIndicator.maxValue = 100.0
progressIndicator.doubleValue = 0.0
progressIndicator.style = .bar
dockTile.contentView = progressIndicator
dockTile.display()
//// Update the progress bar for demonstration
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.updateProgress(50)
}
}
func updateProgress(_ value: Double) {
progressIndicator.doubleValue = value
NSApp.dockTile.display()
}
}
I need to add an accessory view with a text field to an NSAlert. This works as expected but as my app comes in different languages, the alert looks a bit different depending on the language used:
So I wonder how I can make the text field automatically use the full width of the alert window. I tried to call the alert's layout method and then resize the text field but this seems not work in all cases. Any help would be highly appreciated. Thanks!
Which method allows me to apply larger-than-default rounded corners to a macOS window while maintaining the system’s dynamic, contrasting border – similar to what’s seen in the Control Center popup? (Control Center has a corner radius of 16, the default system window is 10.)
While I know how to closely achieve this effect manually for my plain panel, I'd like to leverage the built-in method and get it for free from the OS.
I’ve spent way more time on this problem than I'm willing to admit, and searched extensively, but haven’t found any solution. I’d really appreciate any pointers.
Thank you.
For a Cocoa project I have this table view controller:
@interface TableViewController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
@property (nonatomic, strong) NSMutableArray *numbers;
@property (nonatomic, strong) NSMutableArray *letters;
@end
#import "TableViewController.h"
@implementation TableViewController
- (NSMutableArray *)numbers
{
if (!_numbers)
{
_numbers = [NSMutableArray arrayWithArray:@[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10"]];
}
return _numbers;
}
- (NSMutableArray *)letters
{
if (!_letters)
{
_letters = [NSMutableArray arrayWithArray: @[@"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j"]];
}
return _letters;
}
// NSTableViewDataSource Protocol Method
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return self.numbers.count;
}
// NSTableViewDelegate Protocol Method
-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString *identifier = tableColumn.identifier;
NSTableCellView *cell = [tableView makeViewWithIdentifier:identifier owner:self];
if ([identifier isEqualToString:@"numbers"])
{
cell.textField.stringValue = [self.numbers objectAtIndex:row];
}
else
{
cell.textField.stringValue = [self.letters objectAtIndex:row];
}
return cell;
}
In the storyboard I created a NSTableView and set up the connection, after running it I get what I expected:
okay, cool, but I have a question:
why is this working even though I haven't created a NSTableView as a property for my ViewController or for my TableViewController?
Also, there's another problem, now I want to add a button to this window such that, every time I click it, a new item should be added to this table(for now it can be anything)
So I created a button and a method for this and linked the action to the story board:
-(IBAction) addNewNumber:(id)sender
{
[_numbers addObject:@"1234"];
[_letters addObject:@"testing"];
}
Now, every time I click this button I can see that this method is indeed being called and that indeed IT IS adding a new member to these arrays, the thing is, the table is not being updated, what gives? Any advice on how I can fix this behavior?
I have a Cocoa application and I'm trying to set up an NSImageView without using story board (using storyboard works just fine tho).
Also, I'm kinda new to Cocoa so any advice is appreciated.
Anyway so here's the deal, I created a class to encapsulate this image:
@interface MyView : NSView
{
@private
NSImageView* imageView;
}
@end
@implementation MyView
-(id) initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if(self)
{
NSRect rect = NSMakeRect(10, 10, 100, 200);
imageView = [[NSImageView alloc] initWithFrame:rect];
NSImage* image = [NSImage imageNamed:@"bob.jpeg"];
[imageView setImageScaling:NSImageScaleNone];
[imageView setImage: image];
[self addSubview: imageView];
}
return self;
}
-(id) init
{
return [self initWithFrame:NSMakeRect(10, 10, 100, 100)];
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
}
@end
Now, in the view controller file, in the viewDidLoad I tried to load add this as a subview to get it to display my image:
- (void)viewDidLoad
{
[super viewDidLoad];
MyView *customView = [[MyView alloc] init];
[self.view addSubview:customView];
}
This kinda works, except that it loads the image twice, I ended up with two images instead of just one like I intended, what gives? what am I doing wrong here?
Is there a SwiftUI version of NSControl.allowsExpansionToolTips? That is, showing a tool tip with the full text when (and only when) a text item is truncated?
Or do I need to use a hosting view to get that behavior?
I am using NSMenuToolbarItem to show a drop-down menu in my NSToolbar. This works as expected when creating an NSMenu beforehand and assign it to the menu property of NSMenuToolbarItem.
However, my menu needs to be built dynamically when the user clicks the dropdown button. To do that, I am using NSMenuDelegate. When creating the menu in the menuNeedsUpdate of the delegate, the first menu item isn't shown to the user. Why?
Menu when using delegate:
Menu when pre-assigning menu:
I also cannot just add a placeholder menu item at the start of the NSMenuToolbarItem as all menu items do show in the overflow menu.
Example code:
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate, NSMenuDelegate {
var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
styleMask: [.titled, .closable, .resizable],
backing: .buffered,
defer: false)
window.makeKeyAndOrderFront(nil)
let toolbar = NSToolbar(identifier: "MainToolbar")
toolbar.delegate = self
window.toolbar = toolbar
}
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return [NSToolbarItem.Identifier("item1"), NSToolbarItem.Identifier("item2")]
}
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return [NSToolbarItem.Identifier("item1"), NSToolbarItem.Identifier("item2")]
}
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier,
willBeInsertedIntoToolbar: Bool) -> NSToolbarItem? {
let item = NSMenuToolbarItem(itemIdentifier: itemIdentifier)
if itemIdentifier == NSToolbarItem.Identifier("item1") {
let menu = NSMenu()
fillMenuWithItems(menu)
item.menu = menu
} else if itemIdentifier == NSToolbarItem.Identifier("item2") {
item.menu = NSMenu()
item.menu.delegate = self
}
return item
}
func menuNeedsUpdate(_ menu: NSMenu) {
menu.removeAllItems()
fillMenuWithItems(menu)
}
func fillMenuWithItems(_ menu: NSMenu) {
menu.addItem(NSMenuItem(title: "Option 1", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Option 2", action: nil, keyEquivalent: ""))
}
}
I use xcode16 and swiftUI for programming on a macos15 system. There is a problem. When I render a picture through mtkview, it is normal when displayed on a regular view. However, when the view is displayed through the .sheet method, the image cannot be displayed. There is no error message from xcode.
import Foundation
import MetalKit
import SwiftUI
struct CIImageDisplayView: NSViewRepresentable {
typealias NSViewType = MTKView
var ciImage: CIImage
init(ciImage: CIImage) {
self.ciImage = ciImage
}
func makeNSView(context: Context) -> MTKView {
let view = MTKView()
view.delegate = context.coordinator
view.preferredFramesPerSecond = 60
view.enableSetNeedsDisplay = true
view.isPaused = true
view.framebufferOnly = false
if let defaultDevice = MTLCreateSystemDefaultDevice() {
view.device = defaultDevice
}
view.delegate = context.coordinator
return view
}
func updateNSView(_ nsView: MTKView, context: Context) {
}
func makeCoordinator() -> RawDisplayRender {
RawDisplayRender(ciImage: self.ciImage)
}
class RawDisplayRender: NSObject, MTKViewDelegate {
// MARK: Metal resources
var device: MTLDevice!
var commandQueue: MTLCommandQueue!
// MARK: Core Image resources
var context: CIContext!
var ciImage: CIImage
init(ciImage: CIImage) {
self.ciImage = ciImage
self.device = MTLCreateSystemDefaultDevice()
self.commandQueue = self.device.makeCommandQueue()
self.context = CIContext(mtlDevice: self.device)
}
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
func draw(in view: MTKView) {
guard let currentDrawable = view.currentDrawable,
let commandBuffer = commandQueue.makeCommandBuffer()
else {
return
}
let dSize = view.drawableSize
let drawImage = self.ciImage
let destination = CIRenderDestination(width: Int(dSize.width),
height: Int(dSize.height),
pixelFormat: view.colorPixelFormat,
commandBuffer: commandBuffer,
mtlTextureProvider: { () -> MTLTexture in
return currentDrawable.texture
})
_ = try? self.context.startTask(toClear: destination)
_ = try? self.context.startTask(toRender: drawImage, from: drawImage.extent,
to: destination, at: CGPoint(x: (dSize.width - drawImage.extent.width) / 2, y: 0))
commandBuffer.present(currentDrawable)
commandBuffer.commit()
}
}
}
struct ShowCIImageView: View {
let cii = CIImage.init(contentsOf: Bundle.main.url(forResource: "9-10", withExtension: "jpg")!)!
var body: some View {
CIImageDisplayView.init(ciImage: cii).frame(width: 500, height: 500).background(.red)
}
}
struct ContentView: View {
@State var showImage = false
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
ShowCIImageView()
Button {
showImage = true
} label: {
Text("showImage")
}
}
.frame(width: 800, height: 800)
.padding()
.sheet(isPresented: $showImage) {
ShowCIImageView()
}
}
}
Before updating to macOS 15 Sequoia, I used to be able to create file bookmarks with this code:
let openPanel = NSOpenPanel()
openPanel.runModal()
let url = openPanel.urls[0]
do {
let _ = try url.bookmarkData(options: [.withSecurityScope])
} catch {
print(error)
}
Now I get an error
Error Domain=NSCocoaErrorDomain Code=256 "Failed to retrieve app-scope key"
These are the entitlements:
com.apple.security.app-sandbox
com.apple.security.files.user-selected.read-write
com.apple.security.files.bookmarks.app-scope
Strangely, my own apps continued working, after updating to macOS 15 some days ago, until a few moments ago. Then it seems that all of a sudden my existing bookmarks couldn't be resolved anymore, and no new bookmarks could be created. What could be the problem?
I have a NSWindow subclass. The window has a custom shape, and thus has a custom contentView which overrides drawRect to draw .
Since the window has a custom shape it cannot use the system provided titlebar.
The problem I'm having is when there are multiple screens, if my window is on the inactive screen (not mainScreen with menu bar) and I move the mouse over to the second monitor and click the window....the menu bar doesn't travel to the screen my app is on after the window is clicked.
This does not happen with any other window. In all other windows, the menu bar moves to the screen once you click a window on that screen. So it appears this is because my window is not using NSWindowStyleMaskTitled. As far as I know, I can't use the system title bar and draw my custom window shape. Abandoning the custom window shape is not an option.
Without going into too many details as to why I care, the menu bar really should travel with first click on my window like other apps.. Is there a way to tell the system (other than using the NSWindowStyleMaskTitled) that clicking on my window should make that screen the "main screen" (bring the menu bar over?
I tried programmatically activating the application, ordering the window to the front, etc. but none of this works. This forces the user to click outside my app window, say on the desktop, to move the menu bar over, which feels wrong.
Thanks in advance if anyone has any suggestions.
Hello all,
Recently I observed a strange behaviour on macOS.
Some apps with UI, after you quit them (right click on the Dock, select Quit or select Quit from the menubar), the apps are not actually quitting immediately, but in a few seconds (including in Activity Monitor the apps are staying alive). Also, if you open the apps again fast, the same PID is kept.
Not all apps do this, some of them, for example WhatsApp.
I'm not referring to closing all windows, but explicitly quitting.
This was not the case in the past. Is there any reason for this? Is some kind of optimisation I'm not aware of?
The actual issue is that in a Swift developed app events like NSWorkspace.didLaunchApplicationNotification
or NSWorkspace.didTerminateApplicationNotification are not triggered.
Is there any way to tell if an app was closed, even if macOS still keeps it around for a few more seconds?
Thank you.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
macOS
Custom Apps
AppKit
Kernel
I need to bring an iOS application to macOS using Catalyst. This application contain parts where it waits for a button to be pressed in the main thread, using
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
in a while loop to allow some dispatching while waiting. I know that this is not good style, but I need to convert this old source code and mentioned that when using this part of code under Catalyst, the main thread will not dispatch. So the button cannot be clicked, and a beach ball appears after two seconds.
I saw a similar construct for native macOS applications:
NSEvent *event= [[NSApplication sharedApplication] nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate dateWithTimeIntervalSinceNow:0.1] inMode:NSDefaultRunLoopMode dequeue:YES];
if (event) {
[[NSApplication sharedApplication] sendEvent:event]; }
but I do not have access to NSEvent and NSApplication in a Catalyst environment.
Question: I there any code snippet which I can use to achieve the above? I do not want to completely rewrite old code if there is a solution for this. Any ideas or hints are highly appreciated.
Thank you!
Markus
Hello.
In my app, I use RegisterEventHotkey to implement global keyboard shortcuts to trigger actions.
Up until macOS Sequoia, I was able to use a keyboard shortcut with option and shift as the modifiers, like option shift 2 (⌥ ⇧ 2).
Now, on macOS Sequoia, using RegisterEventHotkey to register a hotkey with those exact modifiers (option and shift), regardless of the key, fails with the error -9868 (eventInternalErr).
Is this a documented and wanted change, or is this a bug? Other modifier keys (just command, command option, command shift, command control, control shift, etc), all work.
Any insight into this would be appreciated. (Feedback filed: FB15163561)
Thank you,
Matthias
I have a simple cocoa project, it has the default files like AppDelegate.m, AppDelegate.h , ViewController.h and ViewController.m what I want is to set the Window title to the dimension of the current window and update it as the user resizes it.
My Storyboard has an Application Scene, a Window Controller Scene and a test Scene which contains my view:
how do I go about this? should my ViewController or AppController implement NSWindowDelegate ?