Способы поведения базового приложения

Архитектура документа Какао, и NSDocument в частности предоставьте поддержку для многих базовых способов поведения приложений Mac.

Документы автоматически сохраняются

В OS X v10.7 и позже, пользователи не должны сохранять документы явно или быть обеспокоены потерей несохраненных изменений. Вместо этого система автоматически пишет данные документа в диск по мере необходимости. Ваш NSDocument подкласс выбирает в это поведение путем переопределения autosavesInPlace метод класса возвратиться YES. Идеальная базовая линия для документов сохранения меньше - это: данные документа, которые пользователи видят в окне приложения, идентичны данным документа по диску в любом случае. По практическим причинам система не пытается сохранить каждое изменение сразу, но это сохраняет документы достаточно часто и в корректные времена, чтобы гарантировать, что документ в памяти и той на диске является эффективно тем же.

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

Автоматическое сохранение на месте отличается от автоматического сохранения в другом месте

Автоматическое сохранение документа поддерживается реализацией автоматического сохранения на месте. Автоматическое сохранение на месте и сохраняющий автоматически в другом месте обоих защищает от пользователя, теряющего работу вследствие сбоев приложения, паники ядра и сбоев питания. Однако автоматическое сохранение на месте отличается от автоматического сохранения в другом месте, в котором оно перезаписывает фактический файл документа вместо того, чтобы писать новый файл рядом с ним содержащий сохраненное автоматически содержание документа. (Сохраняющийся автоматически на месте выполняет безопасное сохранение путем записи в новый файл сначала, затем перемещения его в место файла документа, когда сделано.) Сохраняющийся автоматически на месте проиллюстрирован на рисунке 5-1.

Рисунок 5-1  , Сохраняющийся автоматически на месте

Архитектура документа все еще использует автоматическое сохранение в другом месте для сохранения документов без названия, имеющих содержание, но явно не сохраненных и названных пользователем. В этом случае документы без названия сохраняются автоматически в ~/Library/Autosave Information. Кроме того, NSDocument сохраняет более ранние версии документов в другом месте, предоставляя пользовательский доступ к предыдущим версиям.

Модель saveless-документов автоматизирует противоаварийную защиту, но сохраняет возможность к пользователям сохранить документы явно. Это также автоматизирует обслуживание многократных более старых версий. Пользователи могут сразу сохранить традиционным способом (путем выбора File> Save a Version или нажатия Command-S). Для документа без названия явная команда Save представляет диалоговое окно, позволяющее пользователю назвать документ и указать расположение, где это должно быть записано в диск.

Вы не должны вызывать autosavesInPlace метод, чтобы узнать, делается ли автоматическое сохранение. Вместо этого архитектура документа передает один из двух новых связанных с автоматическим сохранением перечислителей как NSSaveOperationType параметр к Вашим переопределениям NSDocument начало методов save... и write..., и можно исследовать те значения. Перечислители автосохранения NSAutosaveInPlaceOperation и NSAutosaveElsewhereOperation. Старое NSAutosaveOperation перечислитель эквивалентен NSAutosaveElsewhereOperation и осуждается в OS X v10.7.

Рассмотрите сохраняющуюся автоматически производительность

Прежде чем Вы позволите сохраниться автоматически, рассмотрите производительность сохранения своего приложения. Если Ваше приложение сохраняет быстро, существует мало причины не включить его. Но если Ваше приложение медленно сохраняет, разрешение автоматического сохранения могло бы вызвать периодическое блокирование Вашего пользовательского интерфейса, в то время как происходит сохранение. Так, например, если Вы уже реализовали сохраняющееся автоматически поведение, представленное в OS X v10.4 (отправка setAutosavingDelay: к NSDocumentController объект с ненулевым значением), тогда производительность сохранения Вашего приложения, вероятно, приемлема, и выбирающий в автоматическое сохранение на месте так же просто как переопределение autosavesInPlace возвратиться YES. Иначе, Вы, возможно, сначала должны решить любые проблемы со своей моделью документа или сохранение логики, которая могла препятствовать производительности сохранения.

Проверка безопасности предотвращает неумышленные редактирования

Когда сохранение происходит без пользовательского ведома, для неумышленных редактирований становится проще быть сохраненным на диск, приводя к потенциальной потере данных. Помочь предотвратить сохраняющиеся автоматически неумышленные редактирования, NSDocument выполняет проверку безопасности для определения, когда пользователь открыл документ для чтения ее, но не редактирует ее. Например, если документ не редактировался в течение некоторого промежутка времени, он заблокирован для редактирования и открыт только для чтения. (Период после редактирования, когда документ заблокирован, является опцией в системном предпочтении Машины времени.) NSDocument также проверки на документы, которые находятся в папках, где пользователь обычно не редактирует документы, такой как ~/Downloads папка.

Когда редактирование сделано к документу, NSDocument предлагает пользователю выбор отмены изменения, создания нового документа с изменением или разрешения редактирования. Документ, предотвращающий дисплеи редактирований, Привязал строку заголовка. Пользователь может явно позволить редактировать документа путем щелчка по Заблокированной метке и выбора Unlock во всплывающем меню. Документ, измененный, так как он был в последний раз открыт и поэтому активно сохраняется автоматически на месте дисплеи, Отредактированные в строке заголовка вместо Заблокированного.

Приложение может программно определить, когда документ заблокирован в “режиме просмотра только для чтения” путем отправки его isInViewingMode сообщение. Когда пользователь просматривает старую версию документа, можно использовать эту информацию для предотвращения определенных видов пользовательских действий или изменений. Другая полезная функция управления заблокированными документами NSChangeDiscardable. Можно использовать эту константу, чтобы указать, что определенное изменение редактирования является некритическим и может быть выброшено вместо того, чтобы предложить пользователю. Например, изменение понижения в документе Представления ведущих идей обычно заставляло бы некоторые данные быть сохраненными в документе, но Представление ведущих идей объявляет, что изменение, чтобы быть отбрасываемым, таким образом, пользователь, просматривающий заблокированный документ, может изменить слайды, не будучи предложенным разблокировать его.

Сохранение документа может быть асинхронным

В OS X v10.7 и позже, NSDocument может сохранить асинхронно, так, чтобы данные документа были записаны в файл на фоновом потоке. Таким образом, даже если запись является медленной, пользовательский интерфейс приложения остается быстро реагирующим. Можно переопределить метод canAsynchronouslyWriteToURL:ofType:forSaveOperation: возвратиться YES включить асинхронное сохранение. В этом случае, NSDocument создает отдельный поток записи и вызывает writeSafelyToURL:ofType:forSaveOperation:error: на нем. Однако основной поток остается блокированным, пока объект на потоке записи не вызывает unblockUserInteraction метод.

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

Могут быть отменены некоторые автосохранения

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

Некоторые типы автосохранений могут быть безопасно отменены для разблокирования взаимодействия с пользователем, в то время как некоторым нужно разрешить продолжать, даже при том, что они вызывают значимую задержку. Можно определить, может ли данное автосохранение быть безопасно отменено путем отправки документа autosavingIsImplicitlyCancellable сообщение. Этот метод возвраты YES когда периодическое автоматическое сохранение делается для противоаварийной защиты, например, когда можно безопасно отменить работу сохранения. Это возвращается NO когда Вы не должны отменять сохранение, как тогда, когда документ закрывается, например.

Пользователи могут просмотреть версии документа

Архитектура документа реализует опцию Versions OS X v10.7 в поведении NSDocument. NSDocument подкласс принимает автоматическое сохранение на месте путем возврата YES от autosavesInPlace, как описано в Документах Автоматически Сохраняются, и принятие автоматического сохранения поочередно включает просмотр версии.

После того, как документ назвали и сохранили, пункт меню Save заменяется пунктом меню «Save a Version». Эта команда сохраняет версию документа, идентифицированного по дате и время. И NSDocument иногда создает версию автоматически во время автоматического сохранения. Пользователь может выбрать File> Revert Document, или выбрать Browse All Revisions из всплывающего меню справа от строки заголовка, вывести на экран диалоговое окно, позволяющее пользователю выбрать между последней сохраненной версией или более старой версией. Выбор более старой версии выводит на экран подобный машине времени пользовательский интерфейс, выбирающий среди всех версий документа.

Если пользователь принимает решение восстановить предыдущую версию, содержание текущего документа сохраняется на диске, при необходимости, и содержание файла заменяется теми из выбранной версии. Удержание функциональной клавиши при просмотре версий дает пользователю опцию восстановить копию предыдущей версии, не влияющей на содержание текущего документа. Пользователь может также выбрать и скопировать содержание с версии и вставить их в текущий документ.

Windows Are Restored Automatically

Архитектура документа реализует опцию Resume OS X v10.7, так, чтобы отдельные приложения закодировали только информацию, которая специфична для них и необходима для восстановления состояния их окон.

Архитектура документа реализует следующие шаги в процессе восстановления окна; шаги коррелируют к числам, показанным на рисунке 5-2:

  1. NSWindowController метод setDocument: устанавливает класс восстановления окон документа к классу совместно используемого NSDocumentController объект. NSWindow объект лишает законной силы свое восстановимое состояние каждый раз, когда его изменения состояния путем отправки invalidateRestorableState к себе.

  2. В следующее подходящее время Какао отправляет окно encodeRestorableStateWithCoder: сообщение и окно кодируют идентификационную информацию и информацию о статусе в переданный - в кодере.

  3. Когда система перезапускает, Какао повторно запускает приложение и отправляет restoreWindowWithIdentifier:state:completionHandler: обменивайтесь сообщениями к NSApp объект.

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

    NSApp декодирует класс восстановления для окна, отправляет restoreWindowWithIdentifier:state:completionHandler: обменивайтесь сообщениями к объекту класса восстановления и возвратам YES.

  4. Класс восстановления вновь открывает документ и определяет местоположение его окна. Тогда это вызывает переданный - в обработчике завершения с окном в качестве параметра.

  5. Какао отправляет restoreStateWithCoder: обменивайтесь сообщениями к окну, декодирующему его восстановимое состояние от переданного - в NSCoder объект и восстановления подробные данные его содержания.

  Восстановление Окна рисунка 5-2

Несмотря на то, что предыдущие шаги описывают только восстановление окна, фактически каждый объект, наследовавшийся от NSResponder имеет его собственное восстановимое состояние. Например, NSTextView объектно-ориентированные памяти выбранный диапазон (или диапазоны) текста в его восстановимом состоянии. Аналогично, NSTabView записи объекта его выбранная вкладка, NSSearchField записи объекта критерий поиска, NSScrollView записи объекта его позиция прокрутки, и NSApplication записи объекта z-порядок его окон. NSDocument объект имеет состояние также. Несмотря на то, что NSDocument не наследовался от NSResponder, это реализует многих NSResponder методы, включая методы восстановления, показанные на рисунке 5-2.

Когда приложение повторно запускается, Какао отправляет restoreStateWithCoder: обменивайтесь сообщениями к соответствующим объектам поочередно: сначала к NSApplication объект, затем каждому NSWindow объект, затем к NSWindowController объект, затем к NSDocument объект, и затем к каждому представлению, сохранившему состояние.

Архитектура документа предоставляет поддержку отмены бесплатно

Поддержка отмены в архитектуре документа является встроенной и прямой для реализации. По умолчанию, NSDocument объект имеет свое собственное NSUndoManager объект. NSUndoManager класс позволяет Вам создать вызовы, делающие противоположность предыдущего действия.

Реализация отмены

Ключ к реализации отмены должным образом должен иметь четко определенные примитивы для изменения Вашего документа. Каждый объект модели, плюс NSDocument сам подкласс, должен определить набор примитивных методов, которые могут изменить его. Каждый примитивный метод тогда ответственен за использование менеджера по отмене для постановки в очередь вызовов, отменяющих действие примитивного метода. Например, если Вы решаете это setColor: примитивный метод для одного из Ваших объектов модели, затем в setColor: Ваш объект сделал бы что-то как следующее:

 [[[myDocument undoManager] prepareWithInvocationTarget:self] setColor:oldColor]

Это сообщение заставляет менеджера по отмене создавать и сохранять вызов. Если пользователь позже выбирает Undo, сохраненный вызов вызывается, и Ваш объект модели принимает другого setColor: сообщение, на сей раз со старым цветом. Вы не должны отслеживать то, отменяются ли команды для поддержки восстановления. Фактически, способ, которым работает восстановление, путем наблюдения того, какие вызовы регистрируются, поскольку отмена происходит и записывает их на стеке повторного выполнения.

  Стеки отмены рисунка 5-3 и стеки повторного выполнения

Можно использовать setUndoManager: метод, если Вы должны использовать подкласс или иначе должны изменить менеджера по отмене, используемого документом.

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

Другой аспект хорошей реализации отмены должен обеспечить имена действия так, чтобы пункты меню Undo и Redo могли иметь более дескриптивные заголовки. Имена действия отмены лучше всего определяются в методах действия вместо примитивов изменения в Ваших объектах модели, потому что много примитивных изменений могли бы войти в одно пользовательское действие, или различные пользовательские действия могли бы привести к тем же примитивам, вызываемым по-разному. Приложение Эскиза в качестве примера реализует отмену в методах действия.

Реализация частичной отмены

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

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

Если существуют некоторые изменения, которые Вы не можете отменить, существует два способа обработать ситуацию, когда пользователь вносит такое изменение. Если можно быть абсолютно уверены, что изменение не имеет никакого отношения ни к каким другим изменениям, которые могут произойти с документом (т.е. что-то полностью независимое от всей остальной части содержания документа изменилось), то Вы не регистрируете действия отмены для того изменения. С другой стороны, когда такое изменение имеет место, если изменение действительно имеет некоторое отношение к остальной части содержания документа, удаляет все действия от менеджера по отмене. Такие изменения тогда отмечают точки невозврата в Вашем пользовательском опыте. При разработке приложения и формата документа, необходимо стремиться избежать потребности в этих операциях «точки невозврата».

Управление количеством изменения

Из-за поддержки отмены документ должен хранить больше информации, чем просто, является ли документ грязным или чистым. Если пользователь открывает файл, вносит пять изменений, и затем выбирает Undo пять раз, документ должен еще раз быть чистым. Но если пользователь выбирает Undo только четыре раза, документ все еще грязен.

NSDocument объект проводит подсчет изменения для контакта с этим. Количество изменения может быть изменено путем отправки updateChangeCount: сообщение с одним из поддерживаемых типов изменения. Поддерживаемые типы изменения NSChangeDone, NSChangeUndone, и NSChangeCleared. NSDocument сам объект очищает количество изменения каждый раз, когда пользователь сохраняет или возвращается документ. Если документ имеет менеджера по отмене, он наблюдает менеджера по отмене и автоматически обновляет количество изменения, когда изменения сделаны, отменены или восстановлены.

Не поддержка отмены

Если Вы не хотите поддерживать отмену вообще, сначала отправьте setHasUndoManager: сообщение со значением параметра NO к Вашему документу. Это сообщение заставляет документ никогда не получать менеджера по отмене.

Без менеджера по отмене (и без поддержки отмены со стороны Ваших объектов модели), документ не может автоматически отследить свое грязное состояние. Так, если Вы не реализуете отмену, необходимо отправить updateChangeCount: обменивайтесь сообщениями явно каждый раз, когда редактируется Ваш документ.

Архитектура документа поддерживает устойчивую обработку ошибок

Многие NSDocument и NSDocumentController методы включают как их последний параметр косвенную ссылку на NSError объект. Это методы, создающие документ, пишущие файл, получающие доступ к ресурсу или выполняющие подобную работу.

Пример NSDocumentController метод, берущий параметр ошибок, openUntitledDocumentAndDisplay:error:, который создает новый документ без названия. В случае отказа непосредственно возвращается этот метод nil и, в последнем параметре, косвенно возвраты NSError объект, описывающий ошибку. Прежде, чем вызвать такой метод, клиентский код, интересующийся возможной ошибкой, объявляет NSError переменная объекта и передачи адрес переменной в параметре ошибок. Если клиенты не интересуются ошибкой, они передают NULL в параметре ошибок.

Используя NSError объекты дают приложениям Какао возможность представить намного более полезные сообщения об ошибках пользователю, включая подробные причины состояния ошибки, предложения для восстановления, и даже механизм для попытки программируемого восстановления. Кроме того, дескрипторы AppKit, представляющие ошибку пользователю.

Если Вы переопределяете метод, берущий параметр ошибок, и Вы вызываете реализацию суперкласса, Вы не должны устанавливать outError самостоятельно. Передайте его ошибочный параметр, что Ваше переопределение получило, когда вызвано.

Если Вы переопределяете такой метод для предотвращения некоторого действия, но Вы не хотите, чтобы ошибочное предупреждение было представлено пользователю, возвратите ошибочный объект, домен которого NSCocoaErrorDomain и чей код NSUserCancelledError. Платформа AppKit представляет ошибки через NSApplication реализации presentError: и presentError:modalForWindow:delegate:didPresentSelector:contextInfo: методы, объявленные NSResponder. Те реализации тихо игнорируют ошибки, домен которых NSCocoaErrorDomain и чей код NSUserCancelledError. Так, например, если бы Ваше переопределение хотело избежать представлять ошибку пользователю, то оно могло бы установить ошибочный объект как показано в следующем фрагменте:

if (outError) {
    *outError = [NSError errorWithDomain:NSCocoaErrorDomain
                                    code:NSUserCancelledError userInfo:nil];
}

Для получения дальнейшей информации о NSError обработка видит Руководство по программированию Обработки ошибок.