问题描述
在macOS 11上,Apple引入了一个名为NSSearchToolbarItem
的新NSToolbarItem,当焦点切换到工具栏项目时,该工具会自动调整大小以适应键入。
苹果在这里说这与旧版本的macOS向后兼容:https://developer.apple.com/wwdc20/10104(11:50分钟)
但是,从macOS 13的界面生成器中使用NSSearchToolbarItem
启动我的应用程序时,使用以下特定于应用程序的信息会使我的应用程序崩溃:
***由于未捕获的异常'NSInvalidUnarchiveOperationException'而终止应用程序,原因:'*** -[NSKeyedUnarchiver encodeObjectForKey:]:无法为密钥(NS.objects)解码类(NSSearchToolbarItem)的对象;上课可能是 在源代码中定义或未链接的库终止 带有NSException类型的未捕获异常
在10.15上启动它可以正常工作。我还无法测试10.14。
有什么想法吗?
解决方法
在没有任何代码的情况下在故事板中添加项目可以正常工作,我刚刚测试过。所以可能你在代码中做错了什么。或者在最新的 XCode 中修复。
到目前为止,我发现这仅适用于 Catalina,即使在 Mojave 上也会崩溃。根据@ThomasTempelmann 的说法,它在 XCode 12.5.1 中更好,但我还没有测试过。
,有两种方法可以解决这个问题:
1。使用 Xcode 12.5.1 或更高版本
使用 Xcode 12.5.1 或更高版本构建应用程序,这似乎已经修复了与 10.14 之前系统的兼容性。
2.在代码中添加 NSSearchToolbarItem
如果您仍然希望能够使用较旧的 Xcode 版本(即 Xcode 11 及更早版本)打开项目,则不能将新的 NSSearchToolbarItem 放入故事板,否则较旧的 Xcode 版本将拒绝打开它。
在这种情况下,您将继续使用带有 NSToolbarItem
控件的经典 NSSearchField
。挑战在于在运行 macOS 11 或更高版本时将其替换为 NSSearchToolbarItem
。
我尝试了几种方法,例如从工具栏中显式删除经典搜索工具栏项,然后添加新项,并实现委托功能来提供它。虽然这样做有效,但在让用户自定义工具栏时会出现问题:然后对话框将继续显示旧的搜索项和新的搜索项。解决此问题的唯一方法是访问私有函数(_setAllowedItems
和 _setDefaultItems
),但我对此并不满意。
我终于找到了这个相当的解决方案:
- 创建一个新的自定义类,将其命名为
SmartSearchToolbarItem
,并使其成为NSToolbarItem
的子类。 - 在故事板中,将搜索字段的类从
NSToolbarItem
更改为SmartSearchToolbarItem
。 - 将以下代码添加到
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];
}
}
}