I'm experiencing a weird issue where NSPopover doesn't show content. What's also strange is that when inspecting view in Xcode Debug View Hierarchy, it renders all the views as expected.
Here is how the Xcode Debug View Hierarchy looks like:
I just don't understand the issue; why is LoginViewController's view not shown. This issue started with macOS Sonoma.
Here is the Popover setup:
{
_popover = NSPopover.new;
_popover.animates = NO;
_popover.behavior = NSPopoverBehaviorApplicationDefined;
NSViewController* vc;
if (user == nil)
{
vc = LoginViewController.new;
}
else
{
vc = MessageViewController.new;
}
_popover.contentViewController = [RootViewController.alloc initWithRootViewController:vc];
[_popover.contentViewController loadView];
_statusItem = [NSStatusBar.systemStatusBar statusItemWithLength:24];
_statusItem.button.action = @selector(onPress);
_statusItem.button.target = self;
[self reloadPopoverTrayImageForce:YES];
}
And here is how Popover's RootViewController is setup. I mean nothing out-of-standard here, just embedding the child view controller and his view to parent's view controller.
{
self.view = NSView.new;
self.view.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.containerView];
if (self.rootViewController)
{
[self addChildViewController:self.rootViewController];
[self.containerView addSubview:self.rootViewController.view];
self.rootViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
id r = @{ @"root": self.rootViewController.view };
[self.containerView addFor:r constraints:@"|[root]|"];
[self.containerView addFor:r constraints:@"V:|[root]|"];
}
[self.view addSubview:self.footerView];
[self reloadConstraints];
id v = @{
@"container": self.containerView,
@"footer": self.footerView
};
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:self.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual
toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:WIDTH]];
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual
toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:HEIGHT]];
[self.view addFor:v constraints:@"|[container]|"];
[self.view addFor:v constraints:@"|[footer]|"];
[self.view addFor:v constraints:@"V:|[container]-0-[footer(44)]|"];
}
I found the root cause. One of the popover view's subviews was my custom NSView which overrides drawRect method:
- (void) drawRect:(NSRect)dirtyRect
{
NSLog(@"DIRTY RECT: %@", NSStringFromRect(dirtyRect));
[colorSeparator setFill];
NSRectFill(dirtyRect);
[super drawRect:dirtyRect];
}
but it gets weird rect as parameter:
DIRTY RECT: {{-13, -56}, {426, 476}}
DIRTY RECT: {{-13, -411}, {426, 476}}
So I just removed that method and set the background color via layer:
@implementation CDSeparatorView
- (instancetype) init
{
self = [super init];
if (self)
{
[self setupInstance];
}
return self;
}
- (instancetype) initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self)
{
[self setupInstance];
}
return self;
}
- (instancetype) initWithCoder:(NSCoder*)coder
{
self = [super initWithCoder:coder];
if (self)
{
[self setupInstance];
}
return self;
}
- (void) setupInstance
{
self.translatesAutoresizingMaskIntoConstraints = NO;
self.wantsLayer = YES;
self.layer.backgroundColor = SREG.theme.colorSeparator.CGColor;
}
@end
and now the app is drawing the content just fine.