3

会感谢一些指导,因为我对核心数据问题有点不了解。我想创建一个带有 NSSortDescriptor 的 NSFetchRequest ,它使用基于一对多关系的依赖属性。

对于苹果来说,文档说你不能这样做。让我感到困惑的是,只有当我将它用作 NSSortDescriptor 的一部分时,它才不起作用。在请求的 NSPredicate 和我的 ManagedObject 子类中它可以工作。

简而言之,我有一个简单的对象模型,它包含一个可以有许多 Checkin 对象的 Venue 对象。每个 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

到现在为止还挺好。这是来自 TableView 控制器的 fetchRequest

// 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”而终止应用程序,原因:“包含 KVC 聚合的密钥路径不应存在;无法处理签到。@sum.hereNow'

但是对于 MapView 控制器,我有一个类似的 fetchRequest,它工作得很好(我只是将 NSSortDecriptor 设置为使用名称字段)。如果我对 TableView fetchRequest 执行相同操作,那也可以,并且在添加新的签入对象时,地点计数似乎会正确更新。所以在谓词中使用那个keyPath似乎没有问题,只是sortDecriptor。

然而,苹果的文档是这样说的;-

您不能设置对多对关系的依赖关系。例如,假设您有一个 Order 对象,它与 OrderItem 对象的集合具有一对多关系 (orderItems),并且 OrderItem 对象具有 price 属性。您可能希望 Order 对象有一个 totalPrice 属性,该属性取决于关系中所有 OrderItem 对象的价格。您不能通过实现 keyPathsForValuesAffectingValueForKey: 并返回 orderItems.price 作为 totalPrice 的键路径来做到这一点。您必须观察 orderItems 集合中每个 OrderItem 对象的价格属性,并通过自己更新 totalPrice 来响应其值的变化。

这似乎很清楚,但我不明白为什么我可以在谓词中做同样的事情?这是我的第一个核心数据应用程序,所以我对它有点陌生。我已经阅读了几个关于 KVO、KVC 等的问题,但我并没有真正掌握这些问题。正如你所看到的,我真正想做的只是根据他们派生的总“hereNow”计数对一组场地进行排序。也许我正在以完全错误的方式解决这个问题?如果是这样,将不胜感激朝着正确的方向友好引导!

4

1 回答 1

3

我能想到的几点:

  1. 在 SortDescriptor 上,您不能使用 @sum 来计算排序值。你必须在别处计算。我相信这就是为什么它说“包含 KVC 聚合”。因为您使用“键”值来创建排序描述符,所以它必须是对象的实际属性。

  2. 如果 Venue 对象中有派生属性,则不应使其依赖于遍历关系的其他对象。您的“hereNow”属性无法遍历 Checkin 对象以获取要在 Venue 对象上返回的值。我相信派生属性只允许访问同一对象中的其他属性。

一种可能的尝试是将排序描述符键更改为仅尝试 initWithKey:@"hereNow"。

它与您的 MapView 控制器一起使用的原因(我从您的问题中推断)是 name 字段位于同一个对象上,并且不会遍历关系来获取该值。

我可以建议的最好的事情是在您的 Venue 对象上添加一个实际属性,每次更改 Checkins 时都会更新该属性。我知道这不完全是你想要的,但它会起作用。

顺便说一句,keyPathsForValuesAffectingValueForKey 可以在 Mac 上运行,但在 iOS 上不行。它会告诉父对象何时需要更新。请参阅以下的注册依赖键部分:https ://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVODependentKeys.html#//apple_ref/doc/uid/20002179-BAJEAIEE

如果您是 CoreData 的新手,我会推荐 Marcus Zarra 的一本好书: https ://pragprog.com/titles/mzcd/core-data

希望这可以帮助。

于 2011-06-16T13:42:52.403 回答