自动保存不是来自用户的NSDocument模型更改

时间:2014-01-11 08:02:47

标签: objective-c macos cocoa nsdocument autosave

我有一个基于NSDocument的OS X应用程序,而不是使用空白页面创建新文档,而是向用户显示一个面板,以便从中选择模板,例如Apple的Pages.app。

我通过在用户启动新文档时立即手动创建新NSDocument实例并立即在其上设置属性以反映用户为其选择的模板来实现此目的:

MyNSDocumentSubclass *newDoc = [sharedDocumentController makeUntitledDocumentOfType:fileType error:&err];
[newDoc setTemplate:templateChosenByUser]; // autosave doesn't care about this line
[sharedDocumentController addDocument:newDoc];
[newDoc makeWindowControllers];
[newDoc showWindows];

这一功能正常,直到用户决定重新启动计算机或关闭应用程序而不保存:当App Kit的自动保存功能尝试在下次启动时恢复应用程序的前一状态时,它无法为用户模板属性执行此操作因为它从未注意到MyNSDocumentSubclass'模型状态已经改变,并且首先没有自动保存整个文档。相反,可能出于性能优化的原因,只需创建MyNSDocumentSubclass的新实例,用户的模板选择就会丢失。

为了解决这个问题,我添加了

[newDoc updateChangeCount:NSChangeDone];

反映用户选择模板所引入的模型机会。现在,自动保存正确启动并在计算机或应用程序关闭之前保存文档。唯一的缺点(以及我在这里寻求帮助的问题)是,这是错误的做法:NSChangeDone旨在反映用户发起的文档模型的机会。因此,它导致已经在新文档窗口中显示“已编辑”,并在关闭窗口时向用户显示保存面板。但是,用户的模板选择实际上并不是一个应该算作“编辑”的更改,因为它与创建新文档紧密相关。幸运的是,OS X发行说明正好讨论了这个问题并提供了解决方案:

  

某些应用程序使用-updateChangeCount:导致NSDocument自动保存不直接来自用户的更改。例如,在导入非本机文档类型时,某些应用程序会创建包含导入内容的新文档,并调用 - updateChangeCount:以确保文档与这些内容一起自动保存。许多应用程序使用NSChangeDone来实现此目的。但是,由于用户没有明确地导致此更改,因此不希望将此文档转换为草稿。应用程序应谨慎使用正确的NSDocumentChangeType - 在本例中为NSChangeReadOtherContents - 以防止转换为草稿。使用NSChangeDiscardable也会阻止草稿的创建。

不幸的是,[newDoc updateChangeCount:NSChangeReadOtherContents]根本不起作用。它肯定会抑制窗口标题中的“已编辑”,但同时它会阻止自动保存在终止应用程序时执行其工作:文档在下次启动时不会自动保存并丢失其模板属性的值。

那么,我该怎么办? 我希望我新创建的NSDocument子类自动保存用户的模板选择。同时,它实际上只是创建它时不应该显示为已经编辑给用户。

我唯一能想到的是尝试使用NSWindowRestoration协议来保存模板属性,但这显然是错误的。此外,窗口恢复在文档重新打开过程中太迟了。 我的另一个想法是为用户可以选择的每个模板创建几个不同的NSDocument子类(由具有单个UTI的不同文件类型反映),而不是使用我的NSDocument子类上的属性 - 但这感觉不对尽管如此。 否则,我迷路了。谢谢你的帮助。

2 个答案:

答案 0 :(得分:1)

我认为没有一种干净的方法可以做你想做的事情,因为从根本上你试图存储用户在自动保存文件中设置的内容并且没有NSDocument通知文件是“脏的”,当事实上,根据Apple的定义,它很脏。

但是,如果你愿意变得有点脏,我想你可以完成你想要的。一个想法只是做一些事情:

[newDoc updateChangeCount:NSChangeDone];
[newDoc autosaveWithImplicitCancellability:NO completionHandler:^(NSError *errorOrNil){
    [newDoc updateChangeCount:NSChangeCleared];
}];

我知道,我知道,这不干净。

答案 1 :(得分:-1)

您是否尝试使用其中一个 - [NSDocument readFromURL:ofType:error:]或 - [NSDocument readFromData:ofType:error:]方法在空的NSDocument实例中加载模板的内容?