Как предотвратить непрерывное autosaveInPlace с постоянно обновляемым параметром привязки значения - PullRequest
2 голосов
/ 22 ноября 2011

Непрерывно обновляет параметр привязки значения, запускает непрерывные попытки автосохранения (только для каждого введенного вами символа).

Привет всем, это мой первый вопрос здесь!

Надеюсь, я правильно спрошу ...:)

Я пытаюсь добавить механизм автосохранения Lion в мое основанное на документах данных приложение. В моем подклассе NSPersistentDocument я переопределяю метод +(BOOL)autosaveInPlace, возвращающий YES, и все функции работают правильно (сохранение, новые меню, браузер версий…).

Моя проблема в том, что, когда я набираю текстовые поля, привязанные к моей модели, с опцией постоянного обновления значений, система автосохранения запускает операцию сохранения при каждом нажатии клавиши! Вращающийся пляжный мяч не появляется (возможно, потому что мои документы довольно маленькие), но печатание действительно очень медленное.

AutosaveInPlace вызывается при каждом нажатии клавиши, а затем методы saveToURL… и writeToURL….

Я почти ничего не нашел в сети и даже меньше в официальной документации Apple.

В видео «Автосохранение и версии WWDC ’11» инженер приводит неполный пример того, как отменить автосохранение, когда [self autosavingIsImplicitlyCancellable] возвращает YES, но в моем случае этот метод всегда возвращает NO. Это должно быть ожидаемое поведение: значение должно постоянно обновляться, и поскольку файл на диске всегда должен быть идентичен содержимому, которое пользователь видит на экране, это сохранение не должно быть отменено.

В сети я нашел более полезный пример того, как предотвратить инициацию сохранения (переопределение метода save… вместо write…).

 -(void)saveToURL:(NSURL *)url
           ofType:(NSString *)typeName
 forSaveOperation:(NSSaveOperationType)saveOperation
completionHandler:(void (^)(NSError *errorOrNil))completionHandler {
    if (saveOperation == NSAutosaveInPlaceOperation) {
        if ([self isWritingInMyTextField]) {
            completionHandler([NSError errorWithDomain:NSCocoaErrorDomain
                                                  code:NSUserCancelledError
                                              userInfo:nil]);
            return;
            }
        }
    [super saveToURL:url ofType:typeName forSaveOperation:saveOperation completionHandler:completionHandler];
}

Это работает. В случае автосохранения, если мое текстовое поле имеет фокус, я передаю задокументированную ошибку молчания с какао обработчику завершения, и сохранение не происходит, пользовательский интерфейс реагирует, как и раньше. В оригинальном плакате утверждается, что таким образом автосохранение фактически задерживается до окончания текущей активности, но я не уверен в этом.

Моя проблема в том, что я не хочу наблюдать за каждым отдельным текстовым полем для начала / конца редактирования и вынужден вручную запускать самосохранение время от времени, потому что я мешаю системе делать это, пока я ' Я пишу в текстовых полях. Система должна просто понимать, что нецелесообразно запускать сохранение одним нажатием клавиши.

В видео WWDC ’11 инженер указывает на способ проверки активности пользователя с помощью NSRunLoop и событий, но это далеко за пределами моего понимания. Я искал документацию для NSRunLoop, NSEvent, но не могу понять, как получить информацию «пользователь что-то активно печатает!».

Если бы кто-нибудь мог указать мне правильное направление на эту тему, я был бы благодарен.

Было бы лучше, если бы кто-то знал рекомендуемый способ решения этой проблемы!

В заключение я могу прочитать в документации для NSPersistentDocument, что «NSPersistentDocument не поддерживает API асинхронного сохранения NSDocument, так как этот API требует доступа к состоянию документа в нескольких потоках и нарушает требования NSManagedObjectContext». Означает ли это, что если документы вашего приложения не очень маленькие, вы вообще не должны использовать автосохранение? Что ж, Apple, похоже, хочет, чтобы автосохранение стало новым способом работы для всех новых приложений, поэтому я не могу понять, как это может произойти, если разработчикам придется отказаться от основных данных.

Ответы [ 2 ]

2 голосов
/ 25 ноября 2011

Вот мой рабочий ответ.

+(BOOL)autosavesInPlace { return YES; }

-(BOOL)isUserTyping {

    NSUInteger eventType = [[NSApp currentEvent] type];
    return (eventType == NSKeyDown ||
            eventType == NSKeyUp ||
            eventType == NSFlagsChanged);
}

-(void)saveToURL:(NSURL *)url
          ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation
completionHandler:(void (^)(NSError *errorOrNil))completionHandler {

    if (saveOperation == NSAutosaveInPlaceOperation) {

        if ([self isUserTyping]) {

            completionHandler([NSError errorWithDomain:NSCocoaErrorDomain
                                                  code:NSUserCancelledError
                                              userInfo:nil]);

            return;
        }
    }

    [super saveToURL:url ofType:typeName forSaveOperation:saveOperation completionHandler:completionHandler];
}

Я не знаю, является ли мой метод isUserTyping лучшим способом сделать это.Использование видеоинженером WWDC '11 цикла запуска для проверки активности пользователей остается для меня загадкой!

0 голосов
/ 22 ноября 2011

Я считаю, что вам нужно переопределить метод -scheduleAutosaving для NSDocument и запретить ему делать что-либо, пока ваше текстовое поле активно.

Документы для этого метода имеют статус:

Реализация по умолчанию этого метода проверяет, включено ли автосохранение, и, если да, и если [self hasUnautosavedChanges] возвращает YES, планирует NSTimer для вызова autosaveDocumentWithDelegate: didAutosaveSelector: contextInfo: в будущем.

Вы можете переопределить этот метод для контроля, когда происходит именно периодическое автосохранение.

Я бы предложил сделать что-то вроде этого:

- (void)scheduleAutosaving
{
    if([self checkIfOneOfYourTextFieldsIsActive])
         return;
    //no text field is active, so just use the default behaviour
    [super scheduleAutosaving];
}

Обратите внимание, что я не уверен, будет ли это работать, потому что в документации указано, что таймер запланирован для выполнения автосохранения, и я не знаю, возможно ли получить дескриптор этого таймера, чтобы вы могли отменить планированиеэто.

...