Как я могу создать интерфейс master-detail с Core Data и абстрактным объектом?

У Apple есть небольшое руководство по созданию простого интерфейса master-detail. Interface Builder даже автоматически сгенерирует его для вас из объекта Core Data. Однако я пытаюсь сделать что-то более сложное, чем простой пример, и какое-то время я пытался заставить его работать.

У меня есть приложение на основе документов Core Data. Модель включает в себя абстрактный объект Page и несколько конкретных подобъектов Page. Все страницы имеют некоторые общие атрибуты (например, «имя»), и они определены в Page. Очевидно, что субсущности обладают уникальными для них атрибутами.

Я хочу, чтобы интерфейс позволял пользователю видеть все типы страниц в главном списке (NSTableView). Когда они выбирают Страницу, отображаемые поля сведений будут зависеть от типа Страницы.

Вот что у меня есть прямо сейчас:

У меня есть основной файл пера, в котором отображается основной список, а также все поля, общие для страницы. Для каждого типа страницы есть наконечник со своими специфическими полями. В основном файле пера есть основной NSArrayController, который заполняет NSTableView. В каждом из перьев, специфичных для страницы, также есть NSArrayController, так что я могу привязать поля сведений к атрибутам текущего выбора. Все мои NSArrayController настроены одинаково, и все они привязаны к одному и тому же manageObjectContext и тем же selectionIndexes.

Я использую метод Аарона Хиллегасса для обмена представлениями, который он описывает в своей книге Cocoa. Итак, я зарегистрировался для NSTableViewSelectionDidChangeNotifications, и когда я его получаю, он вызывает метод switchView:

switchView просматривает текущий выбранный объект, проверяет, к какому типу относится страница, и подкачивает соответствующий файл пера в соответствии с методом Хиллегасса.

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

Ошибка установки значения для ключевого пути selectionIndexes объекта (из объекта связанного объекта: Страница, количество выбранных объектов: 1): [ valueForUndefinedKey:]: объект NoColPage не соответствует кодированию значения ключа для стороны ключа.

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

Я добавил поле selectionIndexes в MyDocument, чтобы все мои NSArrayController могли привязываться к одному и тому же месту. Я мучился над этим в течение нескольких дней, и я не могу понять это. Любые идеи?

Если это поможет, вот образец проекта, который вы можете скачать. Я извлек из своего проекта только то, что имеет отношение к этой проблеме, в новое фиктивное приложение, которое я использовал для тестирования и экспериментов.

PS: инструмент Interface Builder для создания интерфейса master-detail из объекта Core Data не работает так, как я хочу, для абстрактных объектов. Он только создает поля для атрибутов в суперсущности.

Редактировать: я думаю, что Джошуа что-то задумал, но, к сожалению, это не работает — я постоянно сталкиваюсь с одной и той же проблемой. Сначала мне было тяжело, потому что я не понимал, что -unbind: ожидает строковую константу, а не ключевой путь.

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

Вот соответствующий раздел кода.

-(void) displayViewController: (ManagingVC *) vc withClass:(NSString*) className {

//Try to end editing
NSWindow *w = [box window];
BOOL ended = [w makeFirstResponder:w];
if (!ended) {
    NSBeep();
    return;
}

//The Managing View Controller's NSArrayController
NSArrayController* vcAc = [vc arrCont];

//if the page we're trying to switch to is NOT the same type as the current page we're displaying
//if it is, do nothing.
if (![currPageDisplayed isEqual:className]) {

    //unbind the old view controller
    ManagingVC *oldvc = [viewControllers objectForKey:className];
    NSArrayController* oldsac = [oldvc arrCont];
    [oldsac unbind:@"selectionIndexes"];

    //bind the new view controller
    [vcAc bind:@"selectionIndexes" toObject:self withKeyPath:@"selectionIndexes" options:nil];
    currPageDisplayed = className;

    NSView *v = [vc view];

    //display the new view in an NSBox in the main nib
    [box setContentView:v];
}

}


person Ellie P.    schedule 28.11.2009    source источник
comment
На самом деле это не имеет ничего общего с Core Data — этот тег пока удален.   -  person Joshua Nozzi    schedule 28.11.2009


Ответы (2)


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

Попробуй это:

  1. Удалите крепления в перьях.
  2. Перед добавлением нового представления подключите его привязки в коде.
  3. Перед удалением старого представления отключите его привязки в коде.

Это должно держать все счастливым.

person Joshua Nozzi    schedule 28.11.2009
comment
Спасибо! Я думаю, что вы на что-то, но это все еще делает то же самое. Я добавил больше информации в исходный вопрос. - person Ellie P.; 28.11.2009
comment
Где/как вы получаете className? Это важно. Вы прошли через этот код, чтобы увидеть, действительно ли он ведет себя так, как ожидалось? - person Joshua Nozzi; 28.11.2009
comment
className не проблема, и да, я прошел, и все ведет себя так, как ожидалось. Но все равно отказывается работать. Единственное решение, которое мне удалось найти, — это программный контроль того, какие элементы графического интерфейса пользователя отображаются в основном NIB (таким образом устраняя множественные NIB). Это некрасиво, но пока придется. - person Ellie P.; 03.12.2009

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

Я все еще следую совету Джошуа по отмене привязки перед переключением представления, но сейчас я только привязываю текстовые поля к arrayController.selection.whateverKey

person Ellie P.    schedule 02.12.2009