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

发布于 2024-10-05 19:12:25 字数 1076 浏览 1 评论 0原文

我的应用程序允许用户重命名当前打开的文档。这很简单,而且工作得很好,但有一个我无法弄清楚的非常烦人的错误。当文件被重命名时,AppKit(友善地)会在用户下次尝试保存文档时发出警告。用户说“确定”,一切都会正常进行。当应用程序外部的某些内容更改了文档时,这是有意义的,但当它实际上是由文档本身完成时,则没有意义。

代码是这样的:

-(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 如何处理事情。它不会警告用户有关重命名的信息,因为用户实际上执行了重命名。

我需要做什么?

My application allows the user to rename documents that are currently open. This is trivial, and works fine, with one really annoying bug I can't figure out. When a file is renamed, AppKit (kindly) warns the user the next time they try to save the document. The user says "OK" and everything continues as normal. This makes sense when something external to the application changed the document, but not when it was actually done by the document itself.

The code goes something like this:

-(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]];
}

One would think that expressly setting the new URL and modification date on the document would be enough, but sadly it's not. Cocoa still generates the warning.

I've tried changing the order (setting the new URL on the document, THEN renaming the file) but this doesn't help.

I've also tried a fix suggested by a user on an old post over at CocoaDev:

[self performSelector:@selector(_resetMoveAndRenameSensing)];

Even this does not stop the warning however, and I'm guessing there has to be a proper way to do this using the documented API. How does Xcode handle things when a user clicks a file on the project tree and renames it to something else. It doesn't warn the user about the rename, since the user actually performed the rename.

What do I need to do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

淑女气质 2024-10-12 19:12:25

主要文档中对此没有太多内容。相反,请查看 10.5 发行说明:http:// /developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html%23X10_5Notes 标题下的“NSDocument Checking for Modified Files At Saving Time”

(对于 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];
    }
}

理想情况下,您还需要检查以下可能性:

  1. 要求应用程序重命名文档
  2. 重命名的文件然后由另一个应用程序
  3. 用户 修改/移动去保存文档

此时您希望出现通常的警告表。可能可以通过以下方式完成:

- (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];
}

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

通过这种技术,文档系统应该理解重命名是类似保存操作的一部分,但需要进行大量实验才能确定。

There isn't much on this in the main docs. Instead, have a look at the 10.5 release notes: http://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html%23X10_5Notes under the heading "NSDocument Checking for Modified Files At Saving Time"

(In the case of Xcode, it has a long history and I wouldn't be surprised if if doesn't use NSDocument for files within the project)

It is worth noting that moving a file does not change its modification date, so calling -setFileModificationDate: is unlikely to have any effect.

So one possibility could be to bypass NSDocument's usual warning like so:

- (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];
    }
}

Ideally you also need to check for the possibility of:

  1. Ask app to rename the doc
  2. Renamed file is then modified/moved by another app
  3. User goes to save the doc

At that point you want the usual warning sheet to come up. Could probably be accomplished by something like:

- (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];
}

Otherwise, your only other choice I can see is to call one of the standard save/write methods with some custom parameters that prompt your document subclass to move the current doc rather than actually save it. Would be trickier I think. Perhaps define your own NSSaveOperationType?

With this technique the doc system should understand that the rename was part of a save-like operation, but it would need quite a bit of experimentation to be sure.

无需解释 2024-10-12 19:12:25

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

  • 我重载 saveDocumentWithDelegate:didSaveSelector:contextInfo: 来确定保存 URL 和文档类型(将它们分配给 self);如果旧 fileURL 存在,我将其移动到新位置
  • saveDocumentWithDelegate:didSaveSelector:contextInfo: 内,我将调用重定向到 [self saveToURL:self.fileURL ofType:self.fileType forSaveOperation:NSSaveAsOperation completionHandler: ...] 而不是 [super saveDocumentWithDelegate:didSaveSelector:contextInfo:]

这对我有用。

Much inspired from @Mike's answer, I got the "moved to" message not to show up anymore by re-routing NSSaveOperation to NSSaveAsOperation. In my NSDocument subclass:

  • I overload saveDocumentWithDelegate:didSaveSelector:contextInfo: to determine the save URL and document type (assigning those to self); if the old fileURL exists, I move that to the new location
  • Inside saveDocumentWithDelegate:didSaveSelector:contextInfo: I redirect the call to [self saveToURL:self.fileURL ofType:self.fileType forSaveOperation:NSSaveAsOperation completionHandler: ...] instead of [super saveDocumentWithDelegate:didSaveSelector:contextInfo:]

This works for me.

〆一缕阳光ご 2024-10-12 19:12:25

难道不能以编程方式回答用户的问题吗?
或者您可以在重命名后立即保存,这样用户就能一次性获得所有答案。

我发现这个问题已经存在并运行了一段时间,因此告诉您阅读 参考 我想不会有任何好处..

希望我能有所帮助,尽管它没有不直接解决你的问题

Isn't it possible to programmatically answer the question for the user?
Or you can save immediately after renaming, this way a user gets every answer in one go.

I see that this problem is up and running for some time, so telling you to read the reference won't do any good i guess..

Hope i helped a little bit although it doesn't fix your problem directly

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文