我已经在我的 AppKit (Cocoa) 应用程序中实现了状态恢复。这有效。
但是:如果用户通过双击应用程序保存的文档文件来打开应用程序,那么我希望应用程序不要恢复以前的窗口,而是仅打开在Finder中打开的文档。
问题是状态恢复似乎发生在调用打开文档文件的处理程序之前,因此即使我有办法抑制状态恢复,我也不知道此时待处理的 openURL 调用.
我知道我可以检查启动参数,但这似乎是一种相当肮脏的方式。我认为我应该能够以某种方式从应用程序对象查询存储的文件路径/URL,但我找不到任何东西。或者我可以更改恢复文档与打开文档的顺序吗?到目前为止,我发现这两种情况都发生在
[NSDocument restoreDocumentWindowWithIdentifier:state:completionHandler:]
深处,在completionHandler 函数内部。不过,我找不到低于该功能的可重写函数,我可以对此进行更多控制。我通过在我的 NSDocument 子类中实现
restoreStateWithCoder:
和
encodeRestorableStateWithCoder:
来执行状态恢复。
odoc
AppleEvent,如果调用了该事件,则设置一个标志,使
[NSApp restoreWindowWithIdentifier:]
返回 NO。这是里面的代码
AppDelegate.m
:
static AEEventHandlerUPP openDocHandler = NULL;
static SRefCon openDocRefcon;
static pascal short HandleOpenDocMessage (const AEDesc *theAppleEvent, AEDesc *reply, void* handlerRefcon)
{
// intercepts the "odoc" Event to check if we're about to open any files, and then continues with the original handler
NSAppleEventDescriptor *event = [NSAppleEventDescriptor.alloc initWithAEDescNoCopy:theAppleEvent];
NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
if (url) {
NSString *docType = [NSDocumentController.sharedDocumentController typeForContentsOfURL:url error:nil];
if ([docType isEqualToString:@"..."]) { // I can check for particular types here in case I can open several
[(Application*)NSApplication.sharedApplication setSuppressRestorationOfSearchWindows:YES];
}
}
return openDocHandler (theAppleEvent, reply, openDocRefcon);
}
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
AEGetEventHandler(kCoreEventClass, kAEOpen, &openDocHandler, &openDocRefcon, false);
AEInstallEventHandler(kCoreEventClass, kAEOpen, HandleOpenDocMessage, (__bridge SRefCon)(self), false);
...
内部Application.h
:
@property (assign) BOOL suppressRestorationOfSearchWindows;
内部Application.m
:
- (BOOL)restoreWindowWithIdentifier:(NSString *)identifier state:(NSCoder *)state completionHandler:(void (^)(NSWindow *, NSError *))completionHandler // override
{
if ([identifier isEqualToString:@"MyWindowType"] && self.suppressRestorationOfSearchWindows) {
// prevent window restoration on startup if the user launched this app by opening a file of my particular type
return NO;
} else {
// continue with regular state restoration
return [super restoreWindowWithIdentifier:identifier state:state completionHandler:completionHandler];
}
}
不过感觉像是黑客攻击。