2013-03-27 1 views
4

Я пытаюсь написать простую (игрушечную) программу, которая использует методы NSFilePresenter и NSFileCoordinator для просмотра файла для изменений.Методы NSFilePresenter никогда не вызываются

Программа состоит из текстового представления, которое загружает текстовый файл (hardcoded) и кнопку, которая сохранит файл с любыми изменениями. Идея состоит в том, что у меня есть два экземпляра, и сохранение в одном экземпляре заставит другой экземпляр перезагрузить измененный файл.

Загрузка и сохранение файла отлично работают, но методы 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, который когда-либо вызывается (идет по журналам), представленItemURL (который вызывается четыре раза, когда программа запускается и загружает файл, и три раза каждый раз, когда нажимается кнопка «Сохранить»). заметное влияние на первую очередь.

Может кто-нибудь сказать мне, что я делаю неправильно здесь?

ответ

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! 
    } 

Я не знаю, является ли причина, ваши методы протокола не называют, но это, безусловно, место, чтобы начать. Ну, полагая, что вы еще не разработали то, что было неправильно за последние три года! :-)

 Смежные вопросы

  • Нет связанных вопросов^_^