Автосохранение изменений модели NSDocument, которые не исходят от пользователя

У меня есть приложение OS X на основе NSDocument, которое вместо создания новых документов с пустой страницей показывает пользователю панель для выбора шаблона, как, например, Apple Pages.app.

Я сделал это, вручную создав новый экземпляр NSDocument, когда пользователь запускает новый документ, и немедленно установив для него свойство, чтобы отразить, какой шаблон выбрал для него пользователь:

MyNSDocumentSubclass *newDoc = [sharedDocumentController makeUntitledDocumentOfType:fileType error:&err];
[newDoc setTemplate:templateChosenByUser]; // autosave doesn't care about this line
[sharedDocumentController addDocument:newDoc];
[newDoc makeWindowControllers];
[newDoc showWindows];

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

Чтобы исправить это, я добавил

[newDoc updateChangeCount:NSChangeDone];

чтобы отразить шанс модели, представленный выбором шаблона пользователем. Теперь автосохранение срабатывает правильно и сохраняет документ до выключения компьютера или приложения. Единственный недостаток (и моя проблема, с которой я прошу здесь помощи) заключается в том, что это неправильный способ сделать: NSChangeDone предназначен для отражения шанса на модель документа, инициированного пользователем. Таким образом, это приводит к тому, что «отредактированный» уже отображается в окне нового документа, и отображает панель сохранения для пользователя при закрытии окна. Однако выбор пользователем шаблона на самом деле не является изменением, которое следует считать «редактированием», поскольку оно тесно связано с созданием нового документа. К счастью, в примечаниях к выпуску OS X говорится именно об этой проблеме и предлагается решение:

Некоторые приложения используют -updateChangeCount:, чтобы заставить NSDocument автоматически сохранять изменения, которые не исходят непосредственно от пользователя. Например, при импорте неродного типа документа некоторые приложения создают новый документ с импортированным содержимым и вызывают -updateChangeCount:, чтобы гарантировать автоматическое сохранение документа с этим содержимым. Многие приложения используют для этой цели NSChangeDone. Однако, поскольку пользователь явно не вызывал это изменение, нежелательно превращать этот документ в черновик. Приложения должны использовать правильный NSDocumentChangeType — в данном случае NSChangeReadOtherContents — чтобы предотвратить преобразование в черновик. Использование NSChangeDiscardable также предотвратит создание черновика.

К сожалению, [newDoc updateChangeCount:NSChangeReadOtherContents] вообще не работает. Он, безусловно, подавляет «отредактировано» в заголовке окна, но в то же время не позволяет автосохранению выполнять свою работу при завершении работы приложения: документ не сохраняется автоматически и теряет значение своего свойства шаблона при следующем запуске.

Так что я могу сделать? Я хочу, чтобы мой только что созданный подкласс NSDocument автоматически сохранял выбранный пользователем шаблон. В то же время он не должен показываться пользователю как уже отредактированный, хотя на самом деле он его только что создал.

Единственное, что я могу придумать, это попытаться сохранить свойство шаблона с помощью протокола NSWindowRestoration, но это кажется совершенно неправильным. Кроме того, восстановление окна срабатывает слишком поздно в процессе повторного открытия документа. Другая идея, которая у меня была, состоит в том, чтобы создать несколько разных подклассов NSDocument (отражаемых разными типами файлов с одним UTI) для каждого шаблона, который может выбрать пользователь, вместо использования свойства в моем подклассе NSDocument, но тем не менее это кажется неправильным. Иначе я пропал. Спасибо за вашу помощь.


person Elwisz    schedule 11.01.2014    source источник


Ответы (2)


Я не думаю, что будет чистый способ сделать то, что вы хотите, поскольку, по сути, вы пытаетесь сохранить что-то, что пользователь установил в файле автосохранения, и НЕ иметь уведомления NSDocument, что файл «грязный», когда по определению Apple на самом деле он грязный.

НО, я думаю, вы можете достичь того, чего хотите, если вы готовы немного испачкаться. Одна идея состоит в том, чтобы просто сделать что-то вроде:

[newDoc updateChangeCount:NSChangeDone];
[newDoc autosaveWithImplicitCancellability:NO completionHandler:^(NSError *errorOrNil){
    [newDoc updateChangeCount:NSChangeCleared];
}];

Я знаю, я знаю, это нечисто.

person Wil Shipley    schedule 11.01.2014
comment
Это может быть не совсем чисто, но это прагматичное решение, которое работает нормально. Спасибо! - person Elwisz; 12.01.2014
comment
Написание приведенного выше кода предотвращает сообщение о системной ошибке документа APP_NAME не может быть автоматически сохранено, когда я изменяю документ с помощью кода в приложении на основе документа. Спасибо за то, что поделился этим. - person coolcool1994; 29.03.2018

Пробовали ли вы использовать один из методов -[NSDocument readFromURL:ofType:error:] или -[NSDocument readFromData:ofType:error:] для загрузки содержимого вашего шаблона в пустой экземпляр NSDocument?

person Dalzhim    schedule 07.05.2014