我有一个基于NSDocument的应用程序和一个NSDocumentController子类。我的NSDocument使用文件URL和URL以及使用Web服务的自定义方案。
我使用自定义代码处理大部分加载和保存,包括-saveToURL:ofType:forSaveOperation:completionHandler:
。 +autosavesInPlace
会返回YES
。
我遇到的问题:启动时不会恢复具有自定义URL方案的文档。具有文件URL方案的文档是 - 保存到文件的常规文档和自动保存的无标题文档。
在打开基于服务器的文档并退出应用程序后,重启时似乎没有调用NSDocument方法。特别是,四个初始化程序都不会被调用:
也没有调用NSDocumentController方法-reopenDocumentForURL:withContentsOfURL:display:completionHandler:
。
文件的可恢复状态如何以及何时编码?他们如何以及何时解码?
答案 0 :(得分:13)
NSDocument负责在-encodeRestorableStateWithCoder:
中编码其可恢复状态,NSDocumentController负责解码文档的可恢复状态并在+restoreWindowWithIdentifier:state:completionHandler:
中重新打开文档。请参阅NSDocumentRestoration.h
中的有用评论。
当NSDocument对URL进行编码时,它似乎使用NSURL的书签方法。问题是这些方法仅适用于文件系统URL。 (非文件URL可能会编码,但它们无法正确解码。)
要解决此问题,请覆盖使用自定义方案的NSDocument实例的编码,以及这些文档的解码。
NSDocument子类:
- (void) encodeRestorableStateWithCoder:(NSCoder *) coder {
if ([self.fileURL.scheme isEqualToString:@"customscheme"])
[coder encodeObject:self.fileURL forKey:@"MyDocumentAutoreopenURL"];
else
[super encodeRestorableStateWithCoder:coder];
}
NSDocumentController子类:
+ (void) restoreWindowWithIdentifier:(NSString *) identifier
state:(NSCoder *) state
completionHandler:(void (^)(NSWindow *, NSError *)) completionHandler {
NSURL *autoreopenURL = [state decodeObjectForKey:@"MyDocumentAutoreopenURL"];
if (autoreopenURL) {
[[self sharedDocumentController]
reopenDocumentForURL:autoreopenURL
withContentsOfURL:autoreopenURL
display:NO
completionHandler:^(NSDocument *document, BOOL documentWasAlreadyOpen, NSError *error) {
NSWindow *resultWindow = nil;
if (!documentWasAlreadyOpen) {
if (![[document windowControllers] count])
[document makeWindowControllers];
if (1 == document.windowControllers.count)
resultWindow = [[document.windowControllers objectAtIndex:0] window];
else {
for (NSWindowController *wc in document.windowControllers)
if ([wc.window.identifier isEqual:identifier]) {
resultWindow = wc.window;
break;
}
}
}
completionHandler(resultWindow, error);
}
];
} else
[super restoreWindowWithIdentifier:identifier
state:state
completionHandler:completionHandler];
}
行为或完成处理程序来自Apple在NSDocumentRestoration.h中的方法注释,应该与super
大致相同。
答案 1 :(得分:4)
窗口状态编码由NSWindow
上的两个方法启用。在窗口上调用setRestorable:
将其标记为可以在重新启动时保存和恢复的那个,然后调用setRestorationClass:
可以指定一个将处理重新创建该已保存窗口的类。
默认情况下,AppKit将NSDocumentController
设置为由NSDocument
个对象控制的窗口的恢复类。通过调用由+restoreWindowWithIdentifier:state:completionHandler:
协议定义的方法NSWindowRestoration
来完成实际的恢复。对于文档,NSDocumentController
实现该方法,并根据传递给方法的NSDocument
实例中编码的状态重新创建NSCoder
对象。
因此,从理论上讲,如果您要继承NSDocumentController
并重写该方法,那么您将有机会恢复由状态恢复机制保存的文档。但是,据我所知,NSDocumentController
用于存储状态的密钥没有记录在任何地方,所以我认为没有一种可靠的方法直接从NSDocumentController
存储的状态恢复本身。
为了支持这一点,您可能需要自己编码文档的整个状态,方法是对正在编码的-encodeRestorableStateWithCoder:
实施NSWindow
和/或实现window:willEncodeRestorableState:
委托方法对于窗口。这两种方法都会传递一个NSCoder
实例,您可以用它来编码您的状态。您可以在此处对自定义方案的URL进行编码,以及保存/恢复状态所需的任何其他相关数据。然后,您将在restoreWindowWithIdentifier:state:completionHandler:
方法中解码该状态。
由于您将拥有一些包含常规文件URL的文档,而某些文档包含您的自定义URL,因此我会通过创建一个负责解码文档状态的单独类来实现此目的,并将其设置为仅用于自定义文档的修复类URL,让NSDocumentController
处理带有文件网址的文档。