У Apple есть симпатичное небольшое руководство по созданию простого интерфейса с мастер-деталями. Интерфейсный Разработчик даже автоматически сгенерирует один для вас из сущности Core Data. Однако я пытаюсь сделать что-то более сложное, чем простой пример, и некоторое время я пытался заставить его работать.
У меня есть приложение на основе документов Core Data. Модель включает в себя абстрактную сущность Page и несколько конкретных подразделов Page. Все страницы имеют общие атрибуты (например, «имя»), и они определены в странице. Очевидно, что субъекты имеют уникальные для них атрибуты.
Я хочу, чтобы интерфейс позволял пользователю видеть все типы страниц в основном списке (NSTableView). Когда они выбирают страницу, отображаемые поля сведений будут зависеть от типа страницы.
Вот что у меня сейчас есть:
У меня есть основной файл пера, где отображается основной список, а также все поля, общие для страницы. Есть перо для каждого типа страницы со своими конкретными полями. В главном файле пера есть основной NSArrayController, который заполняет NSTableView. В каждом из перьев, специфичных для страницы, есть NSArrayController, так что я могу связать поля сведений с атрибутами текущего выделения. Все мои NSArrayControllers настроены одинаково, и все они привязаны к одному и тому же managedObjectContext и одному и тому же selectionIndexes.
Я использую метод Аарона Хиллегаса для обмена мнениями, который он описывает в своей книге Какао. Поэтому я зарегистрировался для NSTableViewSelectionDidChangeNotifications, и когда я получаю его, он вызывает метод switchView:
switchView просматривает выбранный в данный момент объект, проверяет, какой это тип страницы, и заменяет соответствующий файл пера в соответствии с методом Хиллегаса.
Все работает нормально, если я только добавляю страницы одного типа, но как только я добавляю страницу второго типа, я получаю эту ошибку:
Ошибка установки значения для пути выбора ключа. Индексы объекта (из объекта привязанного объекта: Страница, количество выбранных объектов: 1): [valueForUndefinedKey:]: объект NoColPage не соответствует значению ключа, кодирующему для стороны ключа.
Последняя часть ошибки имеет смысл: она застревает, пытаясь отобразить неправильное перо, поэтому пытается привязать поля, которые не существуют для этого объекта.
Я добавил поле selectionIndexes в MyDocument, чтобы все мои NSArrayControllers могли связываться с одним и тем же местом. Я мучился из-за этого в течение нескольких дней, и я не могу понять это. Есть идеи?
Если это поможет, вот пример проекта, который вы можете загрузить . Я извлек только вещи, относящиеся к этой проблеме, из моего проекта в новое фиктивное приложение, которое я использовал для тестирования и игры.
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];
}
}