【问题标题】:Backwards compatibility of new NSSearchToolbarItem新 NSSearchToolbarItem 的向后兼容性
【发布时间】:2020-11-08 15:42:59
【问题描述】:

在 macOS 11 中,Apple 引入了一个名为 NSSearchToolbarItem 的新 NSToolbarItem,当焦点切换到工具栏项时,它会自动调整大小以适应打字。

Apple 在这里表示这与旧版本的 macOS 向后兼容:https://developer.apple.com/wwdc20/10104(11:50 分钟)

但是,使用 macOS 10.13 (High Sierra) 上的界面生成器中的 NSSearchToolbarItem 启动我的应用程序时,我的应用程序会因以下应用程序特定信息而崩溃:

*** 由于未捕获的异常“NSInvalidUnarchiveOperationException”而终止应用程序,原因:“*** -[NSKeyedUnarchiver decodeObjectForKey:]:无法解码类对象(NSSearchToolbarItem)的键(NS.objects);班级可能是 在源代码或未链接的库中定义的终止 带有未捕获的 NSException 类型的异常

在 10.15 上启动它可以正常工作。我还不能测试 10.14。

Thomas Tempelmann 于 7 月 6 日更新

事实证明,这是旧 Xcode 12 版本的错误,现在已在 Xcode 12.5.1 中修复。

我打开了一个赏金,因为在 High Sierra 上运行时,我遇到了一个与工具栏内 NSSegmentedControls 大小不正确有关的问题,但事实证明这是一个单独的问题(可以通过手动重置工具栏的minSizemaxSize 到控件的frame.size)。

因此,解决方法是使用 Xcode 12.5.1 或更高版本。

【问题讨论】:

  • image lookup -rn NSSearchToolbarItem 显示 NSSearchToolbarItem 存在于 AppKit 10.15 中,但不存在于 10.13 中。
  • 是的,但 Apple 在会话 10104 中表示,如果您从 nib 文件加载它,它是向后兼容的。它应该用NSToolbarItem 替换为NSSearchField。但显然不是。
  • 顺便说一句,该问题被报告为错误(FB8889904),请参阅developer.apple.com/forums/thread/666033

标签: macos cocoa nstoolbar nstoolbaritem


【解决方案1】:

在没有任何代码的情况下在情节提要中添加项目可以正常工作,我刚刚测试过。所以可能你在代码中做错了什么。或者在最新的 XCode 中已经修复。

到目前为止,我发现这仅适用于 Catalina,即使在 Mojave 上也会崩溃。根据@ThomasTempelmann 的说法,它在 XCode 12.5.1 中更好,但我还没有测试过。

【讨论】:

  • @ThomasTempelmann 感谢您提供的信息,我已经更新了我目前拥有的新信息(在 Mojave 这似乎对我不起作用)。
  • 好吧,我有更完整的答案,但我不能将赏金奖励给自己。享受! :)
【解决方案2】:

有两种方法可以解决这个问题:

1.使用 Xcode 12.5.1 或更高版本

使用 Xcode 12.5.1 或更高版本构建应用程序,wnhich 似乎已修复与 10.14 之前的系统的兼容性。

2.在代码中添加NSSearchToolbarItem

如果您希望仍然能够使用旧 Xcode 版本(即 Xcode 11 和更早版本)打开项目,则不能将新 NSSearchToolbarItem 放入情节提要中,否则旧 Xcode 版本将拒绝打开它。

在这种情况下,您将继续使用经典的NSToolbarItem,其中包含NSSearchField 控件。挑战是在运行 macOS 11 或更高版本时将其替换为 NSSearchToolbarItem

我尝试了几种方法,例如从工具栏中显式删除经典搜索工具栏项,然后添加新项,并实现委托函数来提供它。虽然这样可行,但在让用户自定义工具栏时会引起麻烦:然后对话框将继续显示旧的搜索项和新的搜索项。解决此问题的唯一方法是访问私有函数(_setAllowedItems_setDefaultItems),但我对此并不满意。

我终于找到了这个相当的解决方案:

  1. 创建一个新的自定义类,我们将其命名为SmartSearchToolbarItem,并使其成为NSToolbarItem 的子类。
  2. 在故事板中,将搜索字段的类从 NSToolbarItem 更改为 SmartSearchToolbarItem
  3. 将以下代码添加到SmartSearchToolbarItem 实现中:
#if __MAC_OS_X_VERSION_MAX_ALLOWED < 101600
@interface NSSearchToolbarItem : NSObject
- (instancetype)initWithItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier;
@end
#endif

@implementation SmartSearchToolbarItem

-(instancetype)initWithItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier
{
    self = [super initWithItemIdentifier:itemIdentifier];   // this is necessary even if we won't use it, or we'll crash in Big Sur
    Class cls = NSClassFromString(@"NSSearchToolbarItem");
    if (cls) {
        self = (id) [[cls alloc] initWithItemIdentifier:itemIdentifier];
    }
    return self;
}

这不仅会自动将经典搜索项替换为 Big Sur 中的新搜索项,而且以后,它甚至 - 这是我不太了解的部分 - 仍然可以与连接的 IBActions 和 IBOutlets 一起使用。因此,无需在代码中复制和属性。

修复分段控件

如果您的工具栏中碰巧有分段控件,那么您还需要此代码来调整它们的大小作为位置,因为它们在 Big Sur 与早期 macOS 系统(10.15 和 10.14 都可以)上具有不同的宽度,但如果你也支持 10.13,你肯定需要这个):

- (void)fixSegmentedToolbarItemWidths // call this from `viewWillAppear`
{
    if (@available(macOS 10.14, *)) {
        // no need to set the sizes here
    } else {
        BOOL didChange = NO;
        for (NSToolbarItem *item in self.view.window.toolbar.items) {
            NSControl *control = (NSControl*)item.view;
            if ([control isKindOfClass:NSSegmentedControl.class]) {
                [control sizeToFit];
                NSRect frame = control.frame;
                const int padding = 2;
                item.minSize = NSMakeSize(frame.size.width+padding, item.minSize.height);
                item.maxSize = item.minSize;
                didChange = YES;
            }
        }
        if (didChange) {
            [self.view.window.toolbar validateVisibleItems];
        }
    }
}

示例代码

Github page

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多