Я работаю над приложением, которое работает точно так же, и вот как я это делаю:
В моей базовой модели данных есть 5 основных объектов:
AbstractItem
- абстрактный объект, имеющий атрибуты, общие для всех элементов, например name
, weight
и editable
. Также имеет два отношения: parent
(отношение «один к одному» с AbstractItem
) и children
(отношение «ко многим» к AbstractItem
и обратное значение parent
).
Group
- конкретный дочерний субъект AbstractItem
.
Folder
- конкретный дочерний субъект AbstractItem
. Добавляет отношение «многие ко многим» к базовому объекту Item
.
SmartFolder
- конкретный дочерний субъект Folder
. Добавляет двоичный атрибут predicateData
. Переопределяет метод доступа Folder
"items", чтобы возвращать результаты выполнения запроса на выборку с предикатом, определенным атрибутом predicateData
.
DefaultFolder
- конкретный дочерний субъект SmartFolder
. Добавляет строковый атрибут identifier
.
Для элементов раздела «Библиотека» я вставляю объекты DefaultFolder
и присваиваю им уникальный идентификатор, чтобы можно было легко их извлекать и различать между ними. Я также даю им NSPredicate
, что соответствует тому, что Items
они должны показать. Например, «Music» DefaultFolder
будет иметь предикат для извлечения всех элементов Music, «Podcasts» DefaultFolder
будет иметь предикат для извлечения всех элементов Podcast и т. Д.
Элементы корневого уровня («Библиотека», «Общий ресурс», «Магазин», «Genius» и т. Д.) - это все Group
элементы с nil
родителем. Для групп и папок, которые нельзя редактировать, атрибут editable
имеет значение NO
.
Что касается фактического получения этого материала в вашем outlineView, вам придется самостоятельно реализовать протоколы NSOutlineViewDataSource
и NSOutlineViewDelegate
. Здесь слишком много поведенческой сложности, чтобы выкачивать ее через NSTreeController
. Однако в моем приложении все поведение (даже перетаскивание) заняло менее 200 строк кода (так что это не , что плохо).