Cocoa有大量的整数掩码和代码.例如,NSCommandKeyMask或NSF1FunctionKey,它们在标题中明确定义和记录.
但是,有些可能是古老的,当访问辅助功能属性时,例如获取字形(AXMenuItemCmdGlyph),您将获得一个整数,如111,表示F1(0xf704),或112表示F2(十六进制:0xf705).
有没有简单的方法来处理面具和代码?也许一个能够将111转换为相应的十六进制unicode 0xf704?我的意思是NSEvent.h将NSF1FunctionKey映射到0xf704,但是有一个映射为111到NSF1FunctionKey还是0xf704?
我有一个使用的应用程序NSStatusItem.在小屏幕上,状态栏中没有太多空间.当用户切换到包含大量菜单项的应用程序时,我的状态项将被隐藏.有没有办法得到这个通知?
到目前为止我尝试了什么:
NSNotification被解雇:不statusView是否从视图层次结构中删除了:否isHiddenOrHasHiddenAncestor:没有这是我用来创建状态项的代码.
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
MyStatusView *maView = [[[MyStatusView alloc] initWithFrame:CGRectMake(0, 0, 50, 22)] autorelease];
[statusItem setTitle:@"Ma Status Item"];
[statusItem setView:maView];
Run Code Online (Sandbox Code Playgroud) 我正在写一个Cocoa应用程序,基本上我有一个窗口,我需要在打开另一个窗口之前检查工作表是否打开.谷歌似乎并不知道那一个.如何检查纸张是否打开?
我用Mac OS X Lion和Python 2.7.我是python的新手.谁能告诉我怎么import AppKit和PyObjC到Python.但是我在尝试导入时遇到错误Import Error: No module named AppKit或' Import Error: No module named PyObjC.
尝试easy_install也无济于事.
如何导入这2个模块?
知道NSViewController在窗口内部存档用于恢复(用户界面保存)目的的最佳实践是什么?我试过在窗口控制器的encodeRestorableStateWithCoder:方法中存档它 只是为了发现视图控制器在restoreStateWithCoder:被调用时没有被取消存档 .
// NSWindowController subclass
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
[super encodeRestorableStateWithCoder:coder];
NSViewController* contentViewController = self.contentViewController;
if (contentViewController) {
[coder encodeObject:contentViewController forKey:BSContentViewControllerResumeKey];
}
}
-(void)restoreStateWithCoder:(NSCoder *)coder
{
[super restoreStateWithCoder:coder];
NSViewController* contentViewController = [coder decodeObjectForKey:BSContentViewControllerResumeKey];
if (contentViewController) {
// somehow this never get executed since contentViewController always comes out nil
self.contentViewController = contentViewController;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,此视图控制器包含管理其自己的子视图的其他视图控制器,因此在NSCoder实例中需要一些范围- 只需coder向下传递提供的对象将导致存档中的名称冲突.
提前致谢!
设置:
我开发了一个典型的基于 Cocoa Document的OS X应用程序.
我的目的是支持Apple的用户界面保留功能,以便从以前的应用程序运行中恢复打开的Documents/Windows.
我没有压倒任何相关的方法,例如:
-[NSWindow isRestorable]
-[NSResponder encodeRestorableStateWithCoder:]
-[NSResponder decodeRestorableStateWithCoder:]
-[NSApplication restoreWindowWithIdentifier:state:completionHandler:]
-[NSDocumentController restoreWindowWithIdentifier:state:completionHandler:]
Run Code Online (Sandbox Code Playgroud)
(注意:-[NSWindow isRestorable]在我的文档窗口中YES,默认情况下已经返回.大概这是基于文档的应用程序的一项功能)
在我的与UI Preservation相关的应用程序中,我认为我没有做任何与众不同的事情.
问题:
我的应用程序中的UI保留无效.但它以一种非常奇怪的方式失败了.当我运行我的应用程序时(通过在Xcode中构建和运行它或通过独立运行分发版本),Saved Application State正确创建普通文件夹并使用正确的应用程序状态信息填充.

如果我强制退出我的应用程序(通过突然停止正在运行的Xcode构建或通过Dock Force Quit菜单项),然后重新启动我的应用程序,UI保留功能完美地工作.该应用程序查找存储在Saved Application State文件夹中的信息,并从之前的运行中正确恢复打开的Documents/Windows.
但是,每当我正常退出我的应用程序时,整个Saved Application State文件夹都会被删除(我可以在Finder中看到这种情况).因此,下次启动应用程序时,没有要恢复的存储状态,并且恢复失败.
我跟踪了这个文件夹删除,直到-[NSApplication terminate:]调用后的某个时间发生.
所以我放了一个符号断点unlink(),当然,AppKit中的一些代码是故意删除Saved Application State文件夹及其所有内容.

请注意unlink()来自NSPersistentUI I/O主线程上调用的队列的调用 …
当NSTextField的宽度发生变化时,如何让自动布局自动将NSTextField包装到多行?
我有许多NSTextFields在检查器窗格中显示静态文本(即:标签).当用户调整检查器窗格的大小时,如果需要,我希望右侧标签能够回流到多行.
(Finder的"获取信息"面板执行此操作.)
但是我无法弄清楚自动布局约束的正确组合以允许这种行为.在所有情况下,右侧的NSTextFields拒绝换行.(除非我明确添加允许它的高度约束.)
视图层次结构使得每个灰色条带是包含两个NSTextField的视图,左侧是属性名称,右侧是属性值.当用户调整检查器窗格的大小时,我希望属性值标签根据需要自动调整其高度.
现在的情况:

我希望发生什么:

(请注意,这种行为与我遇到的关于NSTextFields和自动布局的大多数Stack Overflow问题不同.这些问题希望文本字段在用户输入时增长.在这种情况下,文本是静态的,NSTextField配置为看起来像一个标签.)
更新1.0
考虑到@ hamstergene的建议,我将NSTextField子类化并制作了一个示例应用程序.在大多数情况下,它现在可以工作,但现在有一个小的布局问题,我怀疑这是因为NSTextField的框架与自动布局所期望的完全不同步.在下面的屏幕截图中,右侧标签都是垂直间隔的top约束.在调整窗口大小时,Where字段将正确调整大小并进行包装.但是,在Kind我再次调整窗口"一个像素"之前,文本字段不会被推下.
示例:如果我将窗口的大小调整为Where文本字段首次换行的正确宽度,那么我会在中间图像中得到结果.如果我再向窗口调整一个像素,则会Kind正确设置字段的垂直位置.
我怀疑这是因为自动布局正在通过,然后帧被明确设置.我想自动布局在那个传球上没有看到,但是在下一次传球时看到它,并相应地更新位置.
假设这是问题,我如何通知我正在进行的这些更改的自动布局,setFrameSize以便它可以再次运行布局.(而且,最重要的是,不要陷入layout-setFrameSize-layout-etc.的递归状态...)
解
我想出了一个解决方案,似乎与我希望的完全一致.取而代之的子类的NSTextField,我只是覆盖layout的superview的NSTextField问题.在内部layout,我设置preferredMaxLayoutWidth文本字段,然后触发布局传递.这似乎足以使它大部分工作,但它留下了布局短暂"错误"的恼人问题.(见上面的注释).
解决方案似乎是调用setNeedsDisplay然后一切正常工作.
- (void)layout {
NSTextField *textField = ...;
NSRect oldTextFieldFrame = textField.frame;
[textField setPreferredMaxLayoutWidth:NSWidth(self.bounds) - NSMinX(textField.frame) - 12.0];
[super layout];
NSRect newTextFieldFrame = textField.frame;
if (oldTextFieldFrame.size.height != newTextFieldFrame.size.height) {
[self setNeedsDisplay:YES];
}
}
Run Code Online (Sandbox Code Playgroud) 我使用的是NSTableView + CoreData + NSFetchedResultsController的相当标准的设置,相关的视图控制器为NSFetchedResultsControllerDelegate来接收更改。这是来自视图控制器的相关代码位:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?){
print("Change type \(type) for indexPath \(String(describing: indexPath)), newIndexPath \(String(describing: newIndexPath)). Changed object: \(anObject). FRC by this moment has \(String(describing: self.frc?.fetchedObjects?.count)) objects, tableView has \(self.tableView.numberOfRows) rows")
switch type {
case .insert:
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath.item], withAnimation: .effectFade)
}
case .delete:
if let indexPath = indexPath {
tableView.removeRows(at: [indexPath.item], withAnimation: .effectFade)
}
case .update:
if let indexPath = …Run Code Online (Sandbox Code Playgroud) 这是我第一次使用 AppKit 和NSTableView. 它由NSFetchedResultsController核心数据支持。当数据集发生更改时,Notification将发送:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
guard let links = self.fetchedResultsController.fetchedObjects else {
return
}
if self.viewContext.hasChanges {
try? self.viewContext.save()
}
self._links = links
NotificationCenter.default.post(name: .reloadLinkList, object: nil)
}
Run Code Online (Sandbox Code Playgroud)
NotificationCenter.default.publisher(for: .reloadLinkList).receive(on: RunLoop.main).sink { notification in
self.list.tableView.reloadData()
self.list.linksModel.selectedRows = IndexSet([])
}
.store(in: &cancellables)
Run Code Online (Sandbox Code Playgroud)
这对于插入和更新数据非常有用。当我尝试删除某些内容时,我得到:
Thread 1: Fatal error: UnsafeRawBufferPointer with negative count
Run Code Online (Sandbox Code Playgroud)
删除选定对象的代码如下:
Thread 1: Fatal error: UnsafeRawBufferPointer with negative count …Run Code Online (Sandbox Code Playgroud) 我有一个从状态栏运行的 Mac 应用程序。NSStatusItem单击an 时,我显示 anNSWindow而不是标准的NSMenu。
在 Sonoma 之前,当NSStatusItem单击 时,我使用了activate(ignoringOtherApps: true)现已弃用的 API,以确保我的应用程序成为活动应用程序。这非常有效,所以苹果决定用核武器攻击它。
在 Sonoma 上,macOS 现在显示我的窗口,但不激活应用程序,这意味着用户必须单击 ,NSStatusItem然后再次单击窗口,然后才能与我的 UI 交互。当用户单击窗口时,它还会产生非常不和谐的体验,因为活动应用程序最终会切换,但不是在用户期望的时候切换。我的窗口和之前活动的应用程序突然以不同的状态重绘。它很丑。
最糟糕的是,该问题仅在大约 85% 的时间内发生。15% 的情况下,系统会在显示 UI 时激活我的应用程序。我还无法确定它的模式,但这与 AppKit 发行说明相吻合,表明系统“可能”激活我的应用程序。(毫无疑问,如果一些愚蠢的、过度设计的、机器学习的官样文章认为这是值得做的。)
我如何告诉系统,当我的 NSStatusItem 被单击时,我的应用程序需要变为活动状态,因为 (A) 这是用户所期望的,(B) 替代方案看起来 macOS 已损坏?
我尝试过NSApplication.shared.setActivationPolicy()使用两者.accessory和甚至进行设置.regular(即使添加了 Dock 图标和菜单栏),但问题仍然存在。
appkit ×10
cocoa ×6
macos ×5
objective-c ×3
nsstatusitem ×2
swift ×2
autolayout ×1
cocoa-sheet ×1
combine ×1
constants ×1
core-data ×1
macos-sonoma ×1
nsarchiving ×1
nstableview ×1
nswindow ×1
osx-lion ×1
python ×1
resume ×1
xcode ×1