Отображение фиксированных и редактируемых элементов в списке источников
Фон
Я создаю список источников для своего приложения и хочу, чтобы он был структурирован аналогично iTunes с двумя типами элементов:
- "Фиксированные" предметы - они не меняются и не могут быть перемещены - вверху
- Редактируемые элементы внизу, которые могут быть изменены пользователем - перемещаться, переименовываться и т.д. (В примере iTunes, например, "Плейлисты" и "Смарт-плейлисты")
В моей аналогии с iTunes:
(источник: perspx.com)
До сих пор я структурировал свои данные следующим образом:
- Элементы, которые я хочу быть редактируемыми являются "группа" элементы, в виде
Group
лиц Core Data. - Каждый элемент в списке источников представлен как обычный объект Objective-C
SourceListItem
так что я могу связать каждый элемент с заголовком, значком, дочерними элементами и т.д. - Фиксированные элементы в настоящее время представлены экземплярами
SourceListItem
, хранящимися в массиве в моем объекте контроллера.
Вопрос
Я не уверен, как объединить эти два типа элементов в список источников, чтобы фиксированные элементы были вверху и всегда были там и не менялись, а редактируемые элементы - внизу, и их можно было перемещать и редактировать.
Вот идеи, которые я выдвинул до сих пор:
-
Добавьте фиксированные элементы в модель базовых данных. Это означает, что я могу создать сущность, представляющую элементы списка источников, и размещать мои фиксированные и редактируемые элементы в их экземплярах. Затем их можно привязать к столбцу таблицы Outline View с помощью контроллера Array/Tree. Однако это означает, что мне нужно создать новый объект для представления элементов списка источников, а затем синхронизировать Group
с этим. Мне также нужно было бы каким-то образом создать все фиксированные элементы только один раз, и если что-то случится с любым из постоянных файлов хранилища, тогда фиксированные элементы не будут отображаться.
-
Объедините фиксированные элементы с элементами группы. Хотя оба хранятся в отдельных массивах, это может быть сделано в контроллере для моего окна, когда Outline View запрашивает данные (если используется протокол NSOutlineViewDataSource
, а не привязки). Однако это означает, что мне нужно будет создать новый SourceListItem
для каждой группы в контроллере массива (чтобы связать каждую с иконками и другими атрибутами), сохранить их, а затем наблюдать за контроллером группового массива на предмет изменений, чтобы удалить, добавить или изменить экземпляры SourceListItem
когда изменения сделаны в группах.
У кого-нибудь есть лучшие идеи о том, как я могу это реализовать?
Мне бы хотелось, чтобы мое приложение было совместимо с OS X v10.5, поэтому я бы предпочел любые решения, не зависящие от установки Snow Leopard.
Ответы
Ответ 1
Я работаю над приложением, которое имеет такое же поведение, и вот как я это делаю:
У меня есть 5 основных объектов в моей базовой модели данных:
-
AbstractItem
- абстрактный объект, который имеет атрибуты, общие для всех элементов, такие как name
, weight
и editable
. Также имеет два отношения: parent
(to-one отношение к AbstractItem
) и children
(отношение to-many к AbstractItem
и обратное к parent
).
-
Group
- конкретный дочерний объект AbstractItem
.
-
Folder
- конкретный дочерний объект AbstractItem
. Добавляет отношение "многие ко многим" к основному объекту Item
.
-
SmartFolder
- конкретный дочерний объект Folder
. Добавляет двоичный атрибут predicateData
. Переопределяет атрибут отношения Folder
"items" для возврата результатов выполнения запроса на выборку с предикатом, определенным атрибутом predicateData
.
-
DefaultFolder
- конкретный дочерний объект SmartFolder
. Добавляет строковый атрибут identifier
.
Для элементов раздела "Библиотека" я вставляю объекты DefaultFolder
и присваиваю им уникальный идентификатор, чтобы я мог легко их извлекать и различать. Я также даю им NSPredicate
, который соответствует тому, что Items
они должны показывать. Например, "Музыка" DefaultFolder
будет иметь предикат для извлечения всех элементов музыки, "Подкасты" DefaultFolder
будет иметь предикат для извлечения всех элементов Podcast и т.д.
Элементы корневого уровня ( "Библиотека", "Общий", "Магазин", "Гениус" и т.д.) - это все Group
элементы с родителем nil
. Группы и папки, которые не могут быть отредактированы, имеют атрибут editable
, установленный на NO
.
Что касается фактического получения этого материала в вашем outlineView, вам придется реализовать протоколы NSOutlineViewDataSource
и NSOutlineViewDelegate
самостоятельно. Здесь слишком много поведенческой сложности, чтобы выкачать ее через NSTreeController
. Тем не менее, в моем приложении, я получил все поведение (даже перетаскивание) в менее чем 200 строк кода (так что это не так уж плохо).
Ответ 2
Не вводите бессмысленность в набор данных просто для поддержки представления. Это не только противоречит шаблону проектирования MVC, но и добавляет ненужную сложность (т.е. "Больше возможностей для ошибок" ) к самой важной части: управление пользовательскими данными.
Тем не менее, использование Bindings с этим конкретным сценарием - это то, что вызывает столько трений. Почему бы не отказаться от Bindings полностью? Я думаю, что вы на правильном пути, используя протокол NSOutlineViewDataSource, но вы не сделали этого достаточно далеко. Вместо этого полностью полагайтесь на этот (по-прежнему прекрасно действующий и в некотором смысле превосходящий) протокол.
По сути, вы упрощаете упрощение настройки (и легкость уведомления об изменении) для полного контроля над древовидной структурой.