我正在尝试编写一个简单的(玩具)程序,它使用NSFilePresenter和NSFileCoordinator方法来观察文件的变化。
该程序由一个文本视图和一个按钮组成,该视图加载一个(硬编码)文本文件,该按钮将保存包含任何更改的文件。这个想法是,我有两个实例在运行,保存在一个实例中将导致另一个实例重新加载更改后的文件。
加载和保存文件工作正常,但从未调用过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请注意,在applicationDidFinishLaunching中调用reloadFile,并且每次单击保存按钮时都会调用saveFile (通过应用程序委托)。
惟一被调用的NSFilePresenter方法(根据日志)是presentedItemURL (在程序启动和加载文件时调用四次,每次单击保存时调用三次。在第二个实例中单击保存对第一个实例没有明显影响。
有人能告诉我我哪里做错了吗?
发布于 2013-10-13 17:47:30
我在这个问题上挣扎了很长一段时间。对我来说,唯一要调用的方法是-presentedSubitemDidChangeAtURL: (我监视的是目录而不是文件)。我向苹果公司提出了一个技术支持问题,他们的反应是这是一个bug,如果你在监控一个目录,我们现在唯一能做的就是通过-presentedSubitemDidChangeAtURL:来做所有的事情。不确定在监视文件时可以做些什么。
我鼓励任何遇到这个问题的人提交一个bug (https://bugreport.apple.com),以鼓励苹果尽快解决这个问题。
发布于 2016-06-16 04:29:51
(我知道这是一个老问题,但是...:)
首先,我注意到你没有[NSFileCoordinator removeFilePresenter:self]; anywhere (它应该在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!
}我不知道这是否是您的协议方法不被调用的原因,但这肯定是一个开始。好吧,假设你还没有找出过去三年的问题所在!:-)
https://stackoverflow.com/questions/15670720
复制相似问题