Как получить доступ к объектам CoreData на основе отношения «ко многим» другого объекта?

Я изучаю CoreData с помощью примера приложения для инвентаризации. Моя модель данных имеет 2 объекта: «Владение» и «Тип актива». Владения имеют отношение «к одному» к типам активов, называемым «assetType», а типы активов имеют отношение «ко многим» к владениям, называемым «владениями». Каждое Владение имеет только один Тип Актива, но Типы Актива имеют много Владений.

Я хотел бы отсортировать табличное представление по разделам на основе типов активов. Однако мне нужна помощь в заполнении моей структуры данных.

Вот как я буду моделировать свой контроллер табличного представления

NSArray для разделов таблицы: каждый объект раздела в массиве будет представлять собой NSDictionary с двумя ключами: @"Header" — это тип актива, а @"Possessions" — массив имущества этого типа актива.

Я без проблем справлюсь с построением табличного представления из этой структуры. Я также могу обрабатывать выборку типов активов из CoreData в ключ заголовка моего словаря. Где я в тупике, так это в том, как мне воспользоваться преимуществами отношения «ко многим», которые типы активов имеют к владениям, чтобы я мог получить владения в массиве для словаря.

Как мне получить имущество каждого типа активов в массив?

Нужно ли мне делать запрос на выборку с предикатом, чтобы получить имущество, имеющее соответствующий тип актива, или есть более простой способ? - Кажется, это было бы неэффективно, так как пришлось бы проверять все владения на совпадение!?!?!?!?

Является ли отношение ко многим «владениями» объекта AssetType доступным свойством объекта AssetType? Если да, то как мне получить к нему доступ? Что он возвращает?

Я не ищу бесплатный код, но я готов опубликовать свой, если это необходимо. Мне бы очень хотелось узнать, как лучше всего решить эту проблему, и, возможно, указать на полезную информацию в Интернете для достижения этой цели. Я не совсем новичок, но у меня все еще есть проблемы с пониманием CoreData, и до сих пор документы Apple все еще довольно запутывают меня по этому вопросу. Я признателен за любую предложенную помощь.


person vichudson1    schedule 11.04.2012    source источник


Ответы (2)


Если вы создали свой класс AssetType с шаблоном Xcode по умолчанию NSManagedObject (см. изображение)

Файл/Новый/Файл.../Подкласс основных данных/NSManagedObject

у вас должно быть что-то подобное в вашем AssetType.h:

@interface AssetType : NSManagedObject

@property (nonatomic, retain) NSSet *possessions;

@end

@interface AssetType (CoreDataGeneratedAccessors)

- (void) addPossessionsObject:    (Possession *) value;
- (void) removePossessionsObject: (Possession *) value;
- (void) addPossessions:          (NSSet *) value;
- (void) removePossessions:       (NSSet *) value

@end

Таким образом, если у вас есть объект AssetType, вы можете получить доступ ко всем объектам Possession, связанным с ним, через свойство possessions. Однако по умолчанию он не упорядочен, поэтому для доступа к этим объектам в виде массива вам нужно будет вызвать метод -allObjects набора, который возвращает объекты в наборе в виде массива, а затем, возможно, каким-то образом отсортировать эти объекты.

Редактировать:

Кроме того, даже если вы не создали подкласс NSManagedObject таким образом и в нем еще не реализовано свойство possessions, вы можете добавить это свойство в класс точно так же, как указано в приведенном выше примере, и реализовать его в AssetType. м как @dynamic possessions.

person Egor Chiglintsev    schedule 11.04.2012
comment
Спасибо за Ваш ответ. До сих пор у меня есть Possession как подкласс NSManaged Object, но я просто извлекаю типы активов непосредственно из контекста объекта, поскольку до сих пор он использовался только для метки во владенииDetailViewController. Позвольте мне убедиться, что я правильно вас понимаю. Создайте подкласс для AssetType, извлеките объекты AssetType в массив, чтобы использовать их для создания таких словарей. Перебирая этот массив [.. добавьте метку к моему ключу заголовка [метка assetTypevar]...], затем что-то вроде этого для моего массива владений pArray = [assetTypevar owns] allObjects] - person vichudson1; 11.04.2012
comment
Да, pArray = [[assetTypevar possessions] allObjects] должно работать. Отношения ко многим обычно представлены объектами NSSet (за исключением того, что в iOS 5 Apple представила упорядоченные отношения ко многим, которые представлены напрямую как NSArrays, но они не поддерживаются в предыдущих версиях iOS) - person Egor Chiglintsev; 11.04.2012
comment
Спасибо! И последний вопрос. Потребуется ли мне также регенерировать мои классы владения после того, как я создам подкласс AssetType, или они будут в порядке? - person vichudson1; 11.04.2012
comment
Класс владения должен подойти, поскольку генерация класса AssetType создает только файлы AssetType.h и AssetType.m и не затрагивает ничего другого. - person Egor Chiglintsev; 11.04.2012

из того, что я читаю, я подозреваю, что это намного проще, чем вы думаете.

Мне кажется, что вы предусмотрели использование структуры данных словаря для использования в методе tableView:cellForRowAtIndexPath: вашего UITableController, когда вам, вероятно, вообще не нужно его использовать.

Когда вы создаете экземпляр контроллера табличного представления (viewDidLoad: это, вероятно, наиболее подходящее место), просто извлеките свои активы с помощью кода, подобного этому:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Asset" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
    // handle errors here
}

[fetchRequest release];

При необходимости назначьте массив fetchedObjects переменной экземпляра типа NSArray, чтобы вы могли ссылаться на него в нескольких местах в классе UITableViewController, управляющем таблицей. Затем после приведенного выше кода вы можете сделать что-то вроде этого:

self.assets = fetchedObjects;

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

Когда вам нужен список имущества, связанного с активом, он уже есть в каждом объекте актива в вашем массиве (в этом прелесть CoreData, если он на самом деле не создан в памяти, в тот момент, когда вы пытаетесь получить доступ к свойству, CoreData автоматически создать его для вас).

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

Например, это присвоит объект с индексом 0 локальной переменной.

NSManagedObject *asset = [self.assets objectAtIndex:0];

Вы можете получить свой набор вещей с кодом:

NSSet *assetPossessions = [asset valueForKey:"@possessions"];

(при условии, что отношения, определенные в редакторе моделей в xCode, были названы «владениями»)

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

MyManagedAssetObject *asset = [self.assets objectAtIndex:0];
NSSet *assetPossessions = asset.possessions;

Обратите внимание, что в этом примере я предположил, что вы не используете NSFetchedResultsController. На самом деле даже проще управлять таблицей, используя ее, однако, как это часто бывает с программированием, это проще, только если вы знаете, что «еще одна вещь» и поэтому (парадоксально) усложняет ответ. Поскольку вы не упомянули об этом, я предположил, что вы его не используете.

Надеюсь это поможет. Павел

person TheBasicMind    schedule 11.04.2012
comment
о, я должен был упомянуть, что вы можете заказать запрос на выборку - проверьте шаблон кода Xcode для этого (в библиотеке фрагментов кода). Кроме того, при использовании iOS 5.0 вы можете выбрать хранение имущества в активах в виде NSOrderedSet, чтобы порядок сохранялся в объекте CoreData. Если вам нужно больше гибкости в отношении упорядочения, измените порядок NSSet assetsPossessions, сначала преобразовав NSSet (который по своей природе неупорядочен) в NSArray с помощью: NSArray *possessionSetAsArray = [assetPossessions allObjects]; - person TheBasicMind; 11.04.2012
comment
Спасибо за ваш отзыв. Я не использую NSFetchedResultsController. Я использовал книгу, написанную до этого, я считаю, что она была новой для iOS5. Я выбрал структуру массива словарей, потому что это позволило мне иметь более простой код в моем табличном представлении, где моя модель данных уже сгруппирована в разделы под заголовками. Я просто загружаю массив разделов при запуске приложения и обновляю его по мере необходимости во время выполнения для редактирования, удаления, удаления или редактирования владений и активов. Я просто использую свой раздел индексного пути, чтобы получить правильный словарь и строку, чтобы получить то, что мне нужно, из массива. - person vichudson1; 11.04.2012