Objective c 防止以编程方式重命名NSDocument文件时出现警告

Objective c 防止以编程方式重命名NSDocument文件时出现警告,objective-c,cocoa,macos,nsdocument,Objective C,Cocoa,Macos,Nsdocument,我的应用程序允许用户重命名当前打开的文档。这是琐碎的,工作正常,有一个我真的搞不懂的讨厌的bug。重命名文件时,AppKit(善意地)会在用户下次尝试保存文档时发出警告。用户说“OK”,一切正常。当应用程序外部的某些内容更改了文档时,这是有意义的,但当文档本身实际执行了更改时,这是没有意义的 代码是这样的: -(void)renameDocumentTo:(NSString *)newName { NSURL *newURL = [[[self fileURL] URLByDeletingL

我的应用程序允许用户重命名当前打开的文档。这是琐碎的,工作正常,有一个我真的搞不懂的讨厌的bug。重命名文件时,AppKit(善意地)会在用户下次尝试保存文档时发出警告。用户说“OK”,一切正常。当应用程序外部的某些内容更改了文档时,这是有意义的,但当文档本身实际执行了更改时,这是没有意义的

代码是这样的:

-(void)renameDocumentTo:(NSString *)newName {
  NSURL *newURL = [[[self fileURL] URLByDeletingLastPathComponent]
                                   URLByAppendingPathComponent:newName];

  NSFileManager *fileManager = [NSFileManager defaultManager];
  [fileManager moveItemAtURL:[self fileURL] toURL:newURL];
  NSDictionary *attrs = [fileManager attributesForItemAtPath:[newURL path] error:NULL];

  [self setFileURL:newURL];
  [self setFileModificationDate:[attrs fileModificationDate]];
}
有人会认为,在文档上明确设置新的URL和修改日期就足够了,但遗憾的是,事实并非如此。Cocoa仍然会生成警告

我尝试过更改顺序(在文档上设置新的URL,然后重命名文件),但这没有帮助

我还尝试了一个用户在CocoaDev的一篇旧帖子上建议的修复:

[self performSelector:@selector(_resetMoveAndRenameSensing)];
然而,即使这样也不能停止警告,我猜必须有一种正确的方法使用文档化的API来完成这项工作。当用户单击项目树上的文件并将其重命名为其他文件时,Xcode是如何处理的。它不会警告用户重命名,因为用户实际上执行了重命名


我需要做什么?

主要文档中没有太多关于这方面的内容。相反,请看一看10.5发行说明:“NSDocument在保存时检查修改的文件”标题下的内容

(就Xcode而言,它有着悠久的历史,如果不对项目中的文件使用
NSDocument
,我也不会感到惊讶)

值得注意的是,移动文件不会更改其修改日期,因此调用
-setFileModificationDate:
不太可能有任何效果

因此,一种可能是绕过
NSDocument
的常见警告,如下所示:

- (void)saveDocument:(id)sender;
{
    if (wasRenamed)
    {
        [self saveToURL:[self fileURL] ofType:[self fileType] forSaveOperation:NSSaveOperation delegate:nil didSaveSelector:nil contextInfo:NULL];
        wasRenamed = NO;
    }
    else
    {
        [super saveDocument:sender];
    }
}
理想情况下,您还需要检查以下可能性:

  • 要求应用程序重命名文档
  • 重命名后的文件将被另一个应用程序修改/移动
  • 用户去保存文档
  • 在这一点上,你希望出现通常的警告单。可能通过以下方式实现:

    - (void)renameDocumentTo:(NSString *)newName
    {
        // Do the rename
    
        [self setFileURL:newURL];
        wasRenamed = YES; // MUST happen after -setFileURL:
    }
    
    - (void)setFileURL:(NSURL *)absoluteURL;
    {
        if (![absoluteURL isEqual:[self fileURL]]) wasRenamed = NO;
        [super setFileURL:absoluteURL];
    }
    
    - (void)setFileModificationDate:(NSDate *)modificationDate;
    {
        if (![modificationDate isEqualToDate:[self fileModificationDate]]) wasRenamed = NO;
        [super setFileModificationDate:modificationDate];
    }
    

    否则,我能看到的唯一其他选择是使用一些自定义参数调用一个标准的save/write方法,这些参数会提示文档子类移动当前文档,而不是实际保存它。我想这会更棘手。也许可以定义自己的
    NSSaveOperationType


    使用这种技术,文档系统应该理解重命名是类似于保存的操作的一部分,但是需要进行大量的实验才能确定。难道不可能通过编程为用户回答这个问题吗? 或者您可以在重命名后立即保存,这样用户可以一次获得所有答案

    我发现这个问题已经存在了一段时间,所以我想告诉你阅读这篇文章不会有任何好处


    希望我能帮上一点忙,尽管它不能直接解决您的问题。

    受@Mike的回答启发,我通过将
    NSSaveOperation
    重新路由到
    NSSaveAsOperation
    得到了“移动到”消息,不再显示。在my NSDocument子类中:

    • I重载
      saveDocumentWithDelegate:didSaveSelector:contextInfo:
      ,以确定保存URL和文档类型(将它们分配给
      self
      );如果旧文件URL存在,我会将其移动到新位置
    • saveDocumentWithDelegate:didSaveSelector:contextInfo:
      内部,我将调用重定向到
      [self-savetour:self.fileURL of type:self.fileType for saveoperation:NSSaveAsOperation completionHandler:…]
      而不是
      [super-saveDocumentWithDelegate:didSaveSelector:contextInfo:

    这对我来说很有用。

    我已经开始向邦蒂寻求帮助。不幸的是,我真的一事无成。一个简单的测试用例就是创建一个空白的文档应用程序来打开一个.txt文件(或者其他任何文件),添加一个菜单项,其操作将打开的文件重命名为其他文件(并用新的URL更新文档对象)。在重命名后第一次尝试保存文件时,我试图避开警告。哦,如果文档当前正在编辑,这需要起作用。如果存在未保存的更改,则保存到磁盘、关闭文档、移动文件然后重新打开可能会产生不良影响。回答很好,谢谢。我已经尝试了你的第二个建议,但没有成功,尽管它可能会被迫工作,不知何故。我认为您的第一个建议(覆盖saveDocument:并使用一个临时wasname标志)应该可以很好地工作。现在正准备测试它。