2013-03-27 196 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! 
    } 

我不知道這是否是您的協議方法沒有被調用的原因,但它肯定是一個開始的地方。那麼,假設你在過去三年中還沒有弄清楚什麼是錯的! :-)

相關問題