Как осуществить государственную реставрацию по наблюдаемой недвижимости

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

Экземпляр 0x600000001ba0 класса DataController был освобожден, в то время как наблюдатели значения ключа все еще были зарегистрированы в нем.

Я создал минимальный пример, который воспроизводит проблему. Структура выглядит следующим образом:

RestorationExample
|-> Document.h
|-> Document.m // Custom subclass of NSDocument, has DataController property
|-> DataController.h
|-> DataController.m // Controller that needs to be restored
|-> MainWindowController.h
|-> MainWindowController.m // Observes self.document.dataController
|-> MainWindow.xib // Window controlled by MainWindowController

Вы можете загрузить пример проекта отсюда, чтобы упростить настройку: https://github.com/mpflanzer/restoration_example

Document просто создает MainWindowController

- (void)makeWindowControllers {
    [self addWindowController:[[MainWindowController alloc] initWithWindowNibName:@"MainWindow"]];
}

и кодирует / восстанавливает свое свойство dataController

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
    NSLog(@"Document::encode");
    [super encodeRestorableStateWithCoder:coder];
    [coder encodeObject:self.dataController forKey:@"dataController"];
}

- (void)restoreStateWithCoder:(NSCoder *)coder
{
    NSLog(@"Document::restore");
    [super restoreStateWithCoder:coder];
    self.dataController = [coder decodeObjectForKey:@"dataController"];
}

MainWindowController регистрирует себя в качестве наблюдателя в windowDidLoad метод и снятие с учета в windowWillClose, Это как правильно сделать? Или есть другая функция, которая должна использоваться для добавления или удаления наблюдателей?

- (void)windowDidLoad {
    NSLog(@"MainWindowController::windowDidLoad");
    [super windowDidLoad];
    [((Document*)self.document).dataController addObserver:self forKeyPath:@"dataOffset" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:nil];
}

- (void)windowWillClose:(NSNotification *)notification
{
    [((Document*)self.document).dataController removeObserver:self forKeyPath:@"dataOffset"];
}

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

Когда я запускаю пример (и запускается восстановление состояния), я получаю следующий вывод журнала:

2017-04-19 18:57:54.846297+0100 RestorationExample[16829:1225236] Document::init
2017-04-19 18:57:54.846440+0100 RestorationExample[16829:1225236] DataController::init
2017-04-19 18:57:54.887825+0100 RestorationExample[16829:1225236] Document::readFromData
2017-04-19 18:57:54.953205+0100 RestorationExample[16829:1225236] MainWindowController::windowDidLoad
2017-04-19 18:57:54.953386+0100 RestorationExample[16829:1225236] Change data offset: 0
2017-04-19 18:57:54.957346+0100 RestorationExample[16829:1225236] Document::restore
2017-04-19 18:57:54.958678+0100 RestorationExample[16829:1225236] Ignoring exception raised in void _NSPersistentUIExecuteDispatchedBlock(void (^)(void)): An instance 0x600000001c20 of class DataController was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x60000002ae00> (
<NSKeyValueObservance 0x600000056050: Observer: 0x600000088a70, Key path: dataOffset, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x60000005e9c0>
)
2017-04-19 18:57:59.592119+0100 RestorationExample[16829:1225236] Document::encode

Там проблема в том, что makeWindowControllers и поэтому windowDidLoad вызывается до Document был восстановлен. Учитывая этот порядок MainWindowController будет зарегистрирован в качестве наблюдателя и только после Document постараюсь восстановить его dataController свойство в сохраненном состоянии.

Что-то не так, как я реализовал состояние восстановления? Или как добавить / удалить наблюдателя? Я бы ожидал, что Document восстанавливается сначала и только потом makeWindowControllers вызывается.

0 ответов

Другие вопросы по тегам