2013-03-27 136 views
4

我正试图编写一个简单的(玩具)程序,它使用NSFilePresenter和NSFileCoordinator方法来查看文件以进行更改。NSFilePresenter方法永远不会被调用

该程序由一个文本视图加载一个(硬编码)文本文件和一个按钮,将保存文件的任何更改。这个想法是,我有两个实例正在运行,并且在一个实例中保存会导致另一个实例重新加载更改的文件。

加载并保存文件可以正常工作,但永远不会调用NSFilePresenter方法。它全部基于一个名为FileManager的类来实现NSFilePresenter协议。代码如下:

接口:

@interface FileManager : NSObject <NSFilePresenter> 
@property (unsafe_unretained) IBOutlet NSTextView *textView; 

- (void) saveFile; 
- (void) reloadFile; 

@end 

实现:

@implementation FileManager 
{ 
    NSOperationQueue* queue; 
    NSURL* fileURL; 
} 

- (id) init { 
    self = [super init]; 
    if (self) { 
     self->queue = [NSOperationQueue new]; 
     self->fileURL = [NSURL URLWithString:@"/Users/Jonathan/file.txt"]; 
     [NSFileCoordinator addFilePresenter:self]; 
    } 
    return self; 
} 

- (NSURL*) presentedItemURL { 
    NSLog(@"presentedItemURL"); 
    return self->fileURL; 
} 

- (NSOperationQueue*) presentedItemOperationQueue { 
    NSLog(@"presentedItemOperationQueue"); 
    return self->queue; 
} 

- (void) saveFile { 
    NSFileCoordinator* coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self]; 
    NSError* error; 
    [coordinator coordinateWritingItemAtURL:self->fileURL options:NSFileCoordinatorWritingForMerging error:&error byAccessor:^(NSURL* url) { 
     NSString* content = [self.textView string]; 
     [content writeToFile:[url path] atomically:YES encoding:NSUTF8StringEncoding error:NULL]; 
    }]; 
} 

- (void) reloadFile { 
    NSFileManager* fileManager = [NSFileManager defaultManager]; 
    NSFileCoordinator* coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self]; 
    NSError* error; 
    __block NSData* content; 
    [coordinator coordinateReadingItemAtURL:self->fileURL options:0 error:&error byAccessor:^(NSURL* url) { 
     if ([fileManager fileExistsAtPath:[url path]]) { 
      content = [fileManager contentsAtPath:[url path]]; 
     } 
    }]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self.textView setString:[[NSString alloc] initWithData:content encoding:NSUTF8StringEncoding]]; 
    }); 
} 

// After this I implement *every* method in the NSFilePresenter protocol. Each one 
// simply logs its method name (so I can see it has been called) and calls reloadFile 
// (not the correct implementation for all of them I know, but good enough for now). 

@end 

注意,reloadFile被称为applicationDidFinishLaunching和saveFile的被称为每次保存按钮是点击(通过应用代表)。

唯一被调用的(通过日志)调用的唯一的NSFilePresenter方法是presenceItemURL(当程序启动并加载文件时调用四次,每次单击保存时调用三次,单击另一个实例中的save在第一种情况下显着的效果。

谁能告诉我,我做错了什么在这里?

回答

3

我用了好一阵子这个确切问题挣扎。对我来说,那被称为唯一的方法是-presentedSubitemDidChangeAtURL:(我正在监视一个目录而不是一个文件),我打开了一个Apple的技术支持问题,他们的回应是这是一个错误,我们唯一的一件事情是c如果你正在监控一个目录,现在做的一件事是通过-presentedSubitemDidChangeAtURL:来做所有事情。不确定在监视文件时可以做些什么。

我会鼓励任何遇到此问题的人提交错误(https://bugreport.apple.com)以鼓励Apple尽快解决此问题。

1

(我知道这是一个老问题,但... :))

首先,我注意到你没有任何地方[NSFileCoordinator removeFilePresenter:self];(应该是在dealloc)。

其次,你写道:

// After this I implement *every* method in the NSFilePresenter protocol. Each one 
    // simply logs its method name (so I can see it has been called) and calls reloadFile 
    // (not the correct implementation for all of them I know, but good enough for now). 

你是对的:这是不正确的执行!而且你错了:它不够好,因为对于像accommodatePresentedItemDeletionWithCompletionHandler:这样的方法来说,将完成块作为参数是很重要的,实际上你实现时会调用这个完成块。

- (void) savePresentedItemChangesWithCompletionHandler:(void (^)(NSError * _Nullable))completionHandler 
    { 
     // implement your save routine here, but only if you need to! 
     if (dataHasChanged) [self save]; // <-- meta code 
     // 
     NSError * err = nil; // <-- = no error, in this simple implementation 
     completionHandler(err); // <-- essential! 
    } 

我不知道这是否是您的协议方法没有被调用的原因,但它肯定是一个开始的地方。那么,假设你在过去三年中还没有弄清楚什么是错的! :-)

相关问题