Сортировка NSFetchRequest по зависимому свойству с использованием отношения ко многим - PullRequest
3 голосов
/ 28 мая 2011

Буду признателен за некоторые рекомендации, поскольку я немного разбираюсь в проблеме с основными данными.Я бы хотел бы создать NSFetchRequest с NSSortDescriptor, который использует зависимое свойство, основанное на отношении ко многим.

Со стороны Apple в документации сказано, что вы не можете этого сделать.Что меня смущает, так это то, что только когда я использую его как часть NSSortDescriptor, он не работает.В NSP-предикате запроса и в моем подклассе ManagedObject это работает.

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

@interface Venue :  NSManagedObject <MKAnnotation>  {}

@property (nonatomic, readonly, retain) NSNumber * hereNow;

@end

@interface Venue (CoreDataGeneratedAccessors)
- (void)addCheckinsObject:(NSManagedObject *)value;
- (void)removeCheckinsObject:(NSManagedObject *)value;
- (void)addCheckins:(NSSet *)value;
- (void)removeCheckins:(NSSet *)value;

@end

@implementation Venue 

- (NSNumber *)hereNow {

return [self valueForKeyPath:@"checkins.@sum.hereNow"];

}

@interface Checkin :  Update  {}

@property (nonatomic, retain) Venue * venue;
@property (nonatomic, retain) NSNumber * hereNow;

@end

@implementation Checkin 

@dynamic venue;
@dynamic hereNow;

@end

Пока все хорошо.Вот fetchRequest от контроллера TableView

// Create and configure a fetch request with the Venue entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Venue" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];

// Create a predicate to filter the results
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"checkins.@sum.hereNow > 0"];
[fetchRequest setPredicate:predicate];

// Create the sort descriptors array.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"checkins.@sum.hereNow" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];

// Create and initialize the fetch results controller.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                                                                            managedObjectContext:managedObjectContext 
                                                                                              sectionNameKeyPath:nil
                                                                                                       cacheName:@"Venues"];

С таким кодом, как есть, я получаю следующую ошибку

Завершение приложения из-за необработанного исключения «NSInvalidArgumentException», причина: «Keypathсодержащие агрегат KVC там, где его не должно быть;не удалось обработать проверки. @ sum.hereNow '

Но у меня есть аналогичный запрос fetchRequest для контроллера MapView, который работает отлично (там я просто установил NSSortDecriptor для использования поля имени).Если я сделаю то же самое для TableView fetchRequest, это тоже работает, и счетчики мест, по-видимому, корректно обновляются при добавлении новых объектов регистрации.Так что, похоже, нет проблем с использованием этого keyPath в предикате, только sortDecriptor.

однако, в документации Apple это сказано; -

Нельзя установить зависимости от отношений ко многим.Например, предположим, что у вас есть объект Order с отношением ко-многим (orderItems) к коллекции объектов OrderItem, а объекты OrderItem имеют атрибут price.Возможно, вы захотите, чтобы объект Order имел атрибут totalPrice, который зависит от цен на все объекты OrderItem в отношении.Вы не можете сделать это, реализуя keyPathsForValuesAffectingValueForKey: и возвращая orderItems.price в качестве ключевого пути для totalPrice.Вы должны наблюдать за ценовым атрибутом каждого из объектов OrderItem в коллекции orderItems и реагировать на изменения их значений, самостоятельно обновляя totalPrice.

Это кажется достаточно ясным, но тогда я не понимаю, почему яможет сделать то же самое в предикате?Это мое первое приложение Core data, поэтому я немного новичок в этом.Я прочитал несколько вопросов о KVO, KVC и т. Д., С которыми я действительно не справился должным образом.Как вы можете видеть, все, что я на самом деле пытаюсь сделать, это отсортировать коллекцию объектов по их итоговому количеству "hereNow".Возможно, я поступаю об этом совершенно неправильно?Если это так, был бы признателен за дружественный руль в правильном направлении!

1 Ответ

3 голосов
/ 16 июня 2011

Несколько вещей, о которых я могу подумать:

  1. В SortDescriptor вы не можете использовать @sum для вычисления значения сортировки.Вы должны рассчитать это в другом месте.Я полагаю, что именно поэтому он говорит «содержащий агрегат KVC».Поскольку для создания дескриптора сортировки используется значение «ключ», оно должно быть фактическим свойством объекта.

  2. Если у вас есть производное свойство в объекте Venue, выне должен делать это зависимым от других объектов, которые пересекают отношения.Ваше свойство hereNow не может перемещаться к объектам Checkin, чтобы получить значения, которые будут возвращены на объекте Venue.Я полагаю, что производным свойствам разрешен доступ только к другим свойствам в том же объекте.

Одна из возможных вещей, которую можно попробовать, это изменить ключ дескриптора сортировки, чтобы просто попробовать initWithKey: @ "hereNow".

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

Лучшее, что я могу предложить, - добавить фактическое свойство в объект Venue, который обновляется каждый раз, когда вы меняете Checkin.Я знаю, что это не совсем то, что вы хотите, но это будет работать.

Кстати, keyPathsForValuesAffectingValueForKey будет работать на Mac, но не на iOS.Он сообщит родительскому объекту, когда он должен быть обновлен.См. Раздел Регистрация зависимых ключей: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVODependentKeys.html#//apple_ref/doc/uid/20002179-BAJEAIEE

Если вы не знакомы с CoreData, я бы порекомендовал отличную книгу Маркуса Зарры: https://pragprog.com/titles/mzcd/core-data

Надеюсь, это поможет.

...