Управление отношениями упорядоченных основных данных с помощью NSArrayController

Все эти баги типа «NSOrderedSet был добавлен позже и, следовательно, не должен нормально работать с другими компонентами» сводят меня с ума…

(https://twitter.com/kubanekl/status/413447039855640576)

У меня есть два управляемых объекта и упорядоченное отношение 1:N между ними, которое поддерживается экземпляром (или, точнее, подклассом) NSOrderedSet. Я хочу управлять этими отношениями с помощью NSArrayController, чтобы извлечь выгоду из функций, которые он предлагает (управление выбором, привязка контента, привязки к представлениям, таким как NSTableView).

Поскольку NSOrderedSet не является подклассом NSSet, привязка contentSet к NSArrayController не работает с этим отношением. Я нашел следующий поток и попытался реализовать упомянутые там предложения.

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

Второе предложение, представленное в упомянутой ветке, — использовать привязку contentArray и применить оператор @array к пути ключа модели. Я пробовал это, но базовая связь вообще не затрагивалась при добавлении/удалении объектов через NSArrayController.

Другой вариант, который я нашел, — это использование дескрипторов сортировки с привязкой contentSet. Для этого потребуется сделать отношение неупорядоченным, чтобы contentSet привязка работала, и ввести новый атрибут, используемый специально для управления порядком. Кроме того, для реализации этого потребовался бы индивидуальный механизм заказа, что испортило бы модель. Честно говоря, я хотел бы избежать этого решения.

Мой вопрос довольно ясен: есть ли способ управлять упорядоченными отношениями Core Data с помощью NSArrayController? Если да, то какой лучший способ причинить как можно меньше боли?


person Lukas Kubanek    schedule 21.12.2013    source источник


Ответы (1)


Действительно очень печально, что NSArrayController не поддерживает упорядоченные отношения. Как внимательный наблюдатель за технологией привязки, я считаю неоптимальным то, что кажется, что Apple «отказалась» от нее, ничего не сказав. Последним заметным изменением, которое Apple представила в отношении привязок, являются исправления ошибок NSTreeController. Это было, я думаю, с 10,6/10,7. Похоже, Apple больше не хочет трогать технологию креплений. Я не уверен, почему, потому что крепления иногда действительно хороши. Они могут быть «90% решением». Во время прототипирования это нормально. Я использую привязки там, где это имеет смысл, и иметь NSArrayController с поддержкой упорядоченных отношений было бы здорово.

Большинство решений, которые уже были упомянуты, не являются реальными решениями. Но это зависит. Вот о чем следует подумать:

  1. Если вы планируете поддерживать iCloud, вам все равно не следует/нельзя использовать упорядоченные отношения, потому что Core Data в iCloud их не поддерживает.
  2. Поскольку упорядоченные отношения появились довольно недавно, а стремление к упорядоченному набору объектов существовало задолго до них, в Core Data должен быть способ имитировать упорядоченные отношения. Вы уже указали на то, что 99,9% людей, потребляющих Core Data, делали до того, как стали доступны упорядоченные отношения: сортировали по дополнительному атрибуту. Вы указали, что это портит модель, но я не согласен: это правда, что вам нужно добавить дополнительный атрибут к вашей модели, который не обязательно «представляет» истинные данные модели. Но сколько упорядоченных отношений вы планируете иметь в своей модели? Обычно у вас не так много на приложение. Несмотря на то, что это кажется немного грязным, это то, что было сделано многими людьми по крайней мере для трех основных выпусков Core Data (10.4, 10.5 и 10.6). Даже сегодня это решение используется для обратной совместимости или если вы хотите использовать iCloud. Это «прагматичное» решение. Не красиво, а прагматично. Также, пожалуйста, не надо: даже если вы использовали упорядоченные отношения, порядок ваших объектов должен где-то храниться. Если вы используете хранилище SQLite, то наличие упорядоченной связи приводит к тому, что NSSQLiteStore создает для вас дополнительный столбец. Столбец имеет имя: Z_FOK_$RELATIONSHIPNAME. Таким образом, используя упорядоченные отношения, вы просто делаете то, что в любом случае делается за вас под капотом. Это означает, что с чисто технической точки зрения не имеет большого значения, используете ли вы упорядоченные отношения или дополнительный атрибут. Основные технические проблемы остаются прежними. Упорядоченные отношения — это не магия.
  3. Если вы планируете использовать решение «дополнительный атрибут», имейте в виду, что вам нужно часто настраивать значение этого атрибута: каждый раз, когда пользователь меняет порядок с помощью перетаскивания, вы должны изменить значение атрибута. Это кажется расточительным, но на самом деле это не так. Даже в худшем случае: пользователь, который обменивает объект в строке 0 на объект в последней возможной строке, вызывает только 2 изменения атрибута. Сложность тривиального решения для изменений, необходимых для представления любого изменения, которое можно сделать путем перетаскивания в табличном представлении, составляет O(n), где n — количество выбранных строк. На самом деле это не так уж и плохо, поскольку пользователи обычно не переупорядочивают 10000000 строк одновременно, и даже тогда существуют более умные алгоритмы, которые не так сложно реализовать.
  4. Если вы ищете самое чистое решение, вы должны подклассировать NSArrayController и самостоятельно добавить привязки «orderedContentSet». Вы можете узнать, как это сделать, прочитав руководство по теме Cocoa Bindings Programming. Руководство содержит пример: https://developer.apple.com/library/mac/documentation/cocoa/conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html (листинг 2). Плохо в этом то, что вы создаете подкласс NSArrayController, который обычно не подходит. Многие люди склонны создавать подклассы NSArrayController по причинам, которые не оправдывают его подклассов. Однако в этом случае создание подкласса NSArrayController оправдано, если вы хотите использовать самое чистое решение.
  5. Для 3. существуют общие решения, которые многое делают за вас. Не используйте их.
person Christian Kienle    schedule 22.12.2013