Objective c 是否支持在外部编辑器中进行文档更改?

Objective c 是否支持在外部编辑器中进行文档更改?,objective-c,macos,cocoa,nsdocument,Objective C,Macos,Cocoa,Nsdocument,我有一个NSC文档,其中包含一些简单的代码: - (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError { self.string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return YES; } 如果我在外部编辑器中更改文件,如何得到通知以便处理它?我想这里面有

我有一个NSC文档,其中包含一些简单的代码:

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
  self.string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  return YES;
}
如果我在外部编辑器中更改文件,如何得到通知以便处理它?我想这里面有东西,但我找不到


我正在寻找NSC文档中内置的内容。我知道FSEvent,但它的级别似乎太低,无法对大多数基于文档的应用程序执行非常常见的操作。

您想注册到。从10.7开始,您可以观看任意文件


可能重复的。

NSMetadataQuery似乎是无需轮询且cpu开销低的情况下监视文件和文件夹更改的最佳方法

一些用于监视文件夹的基本代码,您只需要将filePattern设置为文件名,而不是通配符*

NSString* filePattern = [NSString stringWithFormat:@"*"];
NSString *watchedFolder = @"not/fake/path";

NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
[query setSearchScopes:@[watchedFolder]];
NSString *itemName = (NSString*)kMDItemFSName;

[query setPredicate:[NSPredicate predicateWithFormat:@"%K LIKE %@", NSMetadataItemDisplayNameKey, filePattern]];

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(queryFoundStuff:) name:NSMetadataQueryDidFinishGatheringNotification object:query];
[nc addObserver:self selector:@selector(queryFoundStuff:) name:NSMetadataQueryDidUpdateNotification object:query];
[query setNotificationBatchingInterval:0.5];
[query startQuery];

- (void)queryFoundStuff:(NSNotification *)notification {
    [query disableUpdates];
    NSLog(@"Notification: %@", notification.name);
    NSMutableArray *results = [NSMutableArray arrayWithCapacity:query.resultCount];

    for (NSUInteger i=0; i<query.resultCount; i++) {
      [results addObject:[[query resultAtIndex:i] valueForAttribute:NSMetadataItemPathKey]];
    }

    // file has updated, do something 

    [query enableUpdates];
}
NSString*filePattern=[NSString stringWithFormat:@“*”];
NSString*watchedFolder=@“not/fake/path”;
NSMetadataQuery*query=[[NSMetadataQuery alloc]init];
[查询集搜索范围:@[watchedFolder]];
NSString*itemName=(NSString*)kMDItemFSName;
[query setPredicate:[NSPredicate predicateWithFormat:@“%K LIKE%@”,NSMetadataItemDisplayNameKey,filePattern];
NSNotificationCenter*nc=[NSNotificationCenter defaultCenter];
[nc addObserver:自选择器:@selector(queryFoundStuff:)名称:NSMetadataQueryDifinishGatheringNotification对象:查询];
[nc addObserver:自选择器:@selector(queryFoundStuff:)名称:NSMetadataQueryIDUpdateNotification对象:查询];
[查询设置NotificationBatchingInterval:0.5];
[查询开始查询];
-(无效)queryFoundStuff:(NSNotification*)通知{
[查询禁用更新];
NSLog(@“Notification:%@”,Notification.name);
NSMutableArray*results=[NSMutableArray阵列容量:query.resultCount];

对于(i=0;i当我在基于文档的应用程序中打开文档,在另一个应用程序中编辑,然后切换回我的应用程序时,使用新数据调用您提到的相同方法(
readFromData:ofType:error:

然后,您可以添加一个布尔实例变量来检查是否由于外部更新而调用它(在我的例子中,我检查我的一个iboutlet是否已初始化:如果未初始化,则第一次加载文档)。您可能希望将使用
字符串
实例变量的代码移动到某个方法中,如果文档已初始化,则可以调用该方法,如下所示:

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
    self.string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if (self.isLoaded)
        [self documentChanged];
    return YES;
}

- (void)windowControllerDidLoadNib:(FCWindowController *)windowController {
    self.isLoaded = YES;
    [self documentChanged];
}

- (void)documentChanged {
    // use self.string as you like
]
class MyDocument: NSDocument {
    // ...

    var canonicalModificationDate: Date!

    override func presentedItemDidChange() {

        guard fileContentsDidChange() else { return }

        guard isDocumentEdited else {
            DispatchQueue.main.async { self.reloadFromFile() }
            return
        }

        DispatchQueue.main.async { self.showReloadDialog() }
    }

    fileprivate func showReloadDialog() {

        // present alert "do you want to replace your stuff?"
    }

    /// - returns: `true` if the contents did change, not just the metadata.
    fileprivate func fileContentsDidChange() -> Bool {

        guard let fileModificationDate = fileModificationDateOnDisk()
            else { return false }

        return fileModificationDate > canonicalModificationDate
    }

    fileprivate func fileModificationDateOnDisk() -> Date? {

        guard let fileURL = self.fileURL else { return nil }

        let fileManager = FileManager.default
        return fileManager.fileModificationDate(fileURL: fileURL)
    }
}

由于OS X v10.7,
NSDocument
提供了一种简单得多的机制,您可以在子类中重写:
-presentedItemDidChange

处理
-presentedItemDidChange
,忽略元数据更改 不过,当元数据发生变化时,仅仅依靠这个回调就可能产生误报。例如,对于存储在Dropbox中的文件,这很快让我感到不安

我在Swift中处理这一问题的方法大致如下:

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
    self.string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if (self.isLoaded)
        [self documentChanged];
    return YES;
}

- (void)windowControllerDidLoadNib:(FCWindowController *)windowController {
    self.isLoaded = YES;
    [self documentChanged];
}

- (void)documentChanged {
    // use self.string as you like
]
class MyDocument: NSDocument {
    // ...

    var canonicalModificationDate: Date!

    override func presentedItemDidChange() {

        guard fileContentsDidChange() else { return }

        guard isDocumentEdited else {
            DispatchQueue.main.async { self.reloadFromFile() }
            return
        }

        DispatchQueue.main.async { self.showReloadDialog() }
    }

    fileprivate func showReloadDialog() {

        // present alert "do you want to replace your stuff?"
    }

    /// - returns: `true` if the contents did change, not just the metadata.
    fileprivate func fileContentsDidChange() -> Bool {

        guard let fileModificationDate = fileModificationDateOnDisk()
            else { return false }

        return fileModificationDate > canonicalModificationDate
    }

    fileprivate func fileModificationDateOnDisk() -> Date? {

        guard let fileURL = self.fileURL else { return nil }

        let fileManager = FileManager.default
        return fileManager.fileModificationDate(fileURL: fileURL)
    }
}
现在,您还必须更新子类中的
canonicalModificationDate

  • 在“是否要替换内容?”警报的回调中,我将其称为
    -ignoreLatestFileChanges
    ,这样您就不会对用户的广告内容唠叨
  • -readFromURL:ofType:error:
    中,或者以读取初始值的内容为结束
  • -dataOfType:error:
    中,或者以任何方式生成要写入磁盘的内容

  • FSEvents
    会起作用吗?寻找NSDocument中内置内容的可能重复。有人在NSFilePresenter中提到了
    presentedItemDidChange
    (哪个NSDocument符合)。查看是否有显示UI的内容,以询问用户做什么。根据文档,-查看文档中的
    -(NSDate*)fileModificationDate
    @TonyArnold需要轮询,这对我来说似乎不是一个解决方案。谢谢!这与另一个问题有点不同。我只对文档内容的更改感兴趣。我希望NSDocument中内置一些内容。