以编程方式创建的 NSToolbar 开始时为空并且不会保存

NSToolbar created programmatically starts empty and won't save

我目前正在尝试编写 Mac 应用程序。这样做时,我在尝试设置 NSToolbar 时遇到了一些特殊问题。

虽然我已经按照 API 文档设置了所有组件,但是当应用程序加载时,工具栏始终是空的。当我打开自定义窗格时,工具栏项目在那里,我可以将它们拖到工具栏中,但是当我退出应用程序并重新启动时,更改就消失了。

注意:我知道你们中的许多人会认为解决此问题的最佳方法是使用界面生成器而不是在代码中进行。这不是我正在寻找的答案 - 我选择在没有 IB 的情况下制作这个应用程序,以便更好地理解 Cocoa 应用程序的内部结构。

我已经(使用 NSLogs)验证了 toolbarAllowedItemIdentifierstoolbarDefaultItemIdentifiers 委托方法在工具栏首次初始化时都没有被调用,但是当您进入自定义面板时它们确实被调用了。

请在下面找到演示此错误的基本应用程序的最小、可验证和完整示例版本。任何可以阐明此事的人都将不胜感激!

谢谢

Defines.h

#define UNUSED(x) (void)(x)
#define TOOLBAR_ONE @"ONE"
#define TOOLBAR_TWO @"TWO"
#define TOOLBAR_IDENT @"TOOLBAR"

#define WINDOW_MASK NSTitledWindowMask | \
   NSClosableWindowMask | \
   NSResizableWindowMask | \
   NSMiniaturizableWindowMask

main.m

#import "BWAppDelegate.h"
#import <AppKit/AppKit.h>

int main(void) {
   @autoreleasepool {
      NSApplication* application = [NSApplication sharedApplication];
      BWAppDelegate* delegate    = [[BWAppDelegate alloc] init];

      application.delegate = delegate;
      [application run];

      return EXIT_SUCCESS;
   }
}

BWAppDelegate.h

#import <Cocoa/Cocoa.h>

#import "BWMainToolbarDelegate.h"

@interface BWAppDelegate : NSObject<NSApplicationDelegate>

@property (atomic, strong) NSWindow*              window;
@property (atomic, strong) BWMainToolbarDelegate* toolbarDelegate;

@end

BWAppDelegate.m

#import <AVFoundation/AVFoundation.h>
#import <AppKit/AppKit.h>
#import <Cocoa/Cocoa.h>

#import "BWAppDelegate.h"
#import "Defines.h"

@implementation BWAppDelegate

@synthesize window, toolbarDelegate;

- (void) applicationDidFinishLaunching: (NSNotification*) aNotification
{
   UNUSED(aNotification);
   NSRect dims = NSMakeRect(0, 0, 300, 300);

   self.window = [[NSWindow alloc] initWithContentRect:dims
                                             styleMask:WINDOW_MASK
                                               backing:NSBackingStoreBuffered
                                                 defer:NO];
   [self.window makeKeyAndOrderFront:nil];
   self.window.toolbar = [[NSToolbar alloc] initWithIdentifier:TOOLBAR_IDENT];
   toolbarDelegate     = [[BWMainToolbarDelegate alloc] initWithToolbar:self.window.toolbar];
}

@end

BWMainToolbarDelegate.h

#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>

@interface BWMainToolbarDelegate : NSObject<NSToolbarDelegate>

- (instancetype) initWithToolbar: (NSToolbar*) theToolbar;

- (NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar*) toolbar;
- (NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar*) toolbar;
- (NSToolbarItem*)   toolbar: (NSToolbar*) toolbar
       itemForItemIdentifier: (NSString*) identifier
   willBeInsertedIntoToolbar: (BOOL) flag;

@end

BWMainToolbarDelegate.m

#import "BWMainToolbarDelegate.h"
#import "Defines.h"

@implementation BWMainToolbarDelegate {
   NSToolbar* toolbar;
}

- (instancetype) initWithToolbar: (NSToolbar*) theToolbar
{
   self = [super init];
   if(self) {
      toolbar = theToolbar;
      toolbar.displayMode = NSToolbarDisplayModeIconAndLabel;
      toolbar.allowsUserCustomization = YES;
      toolbar.autosavesConfiguration = YES;
      toolbar.delegate    = self;
   }
   return self;
}

- (NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar*) theToolbar
{
   UNUSED(theToolbar);
   return @[TOOLBAR_ONE, TOOLBAR_TWO];
}

- (NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar*) theToolbar
{
   UNUSED(theToolbar);
   return @[TOOLBAR_ONE, TOOLBAR_TWO];
}

- (NSToolbarItem*)   toolbar: (NSToolbar*) theToolbar
       itemForItemIdentifier: (NSString*) identifier
   willBeInsertedIntoToolbar: (BOOL) flag
{
   UNUSED(flag);
   NSToolbarItem* returnVal = nil;
   NSString*      label;

   if([theToolbar.identifier isEqualToString:TOOLBAR_IDENT]) {

      if([identifier isEqualToString:TOOLBAR_ONE]) {
         returnVal = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_ONE];
         label     = @"Toolbar One";
      } else if([identifier isEqualToString:TOOLBAR_TWO]) {
         returnVal = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_TWO];
         label     = @"Toolbar TWO";
      }
   }

   returnVal.label        = label;
   returnVal.paletteLabel = label;
   return returnVal;
}

@end

在将工具栏添加到 window 之前设置工具栏的委托。