问题
It's my first post so sorry if I may not respect all the conventions even though I'll try my best. I have always found solutions to my problems on SO before but I'm completely stuck on a rather complex Cocoa problem.
I am trying to achieve a complex sort on a list of CoreData objects. I have a catalog composed of Book objects, which can be part of Saga (first book and its sequels). The simplified structures look like this:
@interface Book : NSManagedObject
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSNumber * tomaison; //volume numbering
@property (nonatomic, retain) Saga *fromSaga;
@interface Saga : NSManagedObject
@property (nonatomic, retain) NSString * title;
I'm trying to perform a query on my CoreData db, on Book:
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:context];
and I need a sort in three steps:
1) Sort by book's Genre (not included in the code above because it's not needed), which is performed with:
NSSortDescriptor* mainSort = [[NSSortDescriptor alloc] initWithKey:@"ofGenre.title" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
2) Sort by Saga title if the book is part of a Saga
NSSortDescriptor* secondarySort = [[SagaTitleSortDescriptor alloc] initWithKey:@"fromSaga" ascending:YES];
Where the custom sort descriptor is defined by:
#define NULL_OBJECT(a) ((a) == nil || [(a) isEqual:[NSNull null]])
@interface SagaTitleSortDescriptor : NSSortDescriptor {}
@end
@implementation SagaTitleSortDescriptor
- (id)copyWithZone:(NSZone*)zone
{
return [[[self class] alloc] initWithKey:[self key] ascending:[self ascending] selector:[self selector]];
}
- (NSComparisonResult)compareObject:(id)object1 toObject:(id)object2
{
if (NULL_OBJECT([object1 valueForKeyPath:[self key]])) {
if (NULL_OBJECT([object2 valueForKeyPath:[self key]]))
return NSOrderedSame;
return NSOrderedDescending;
}
if (NULL_OBJECT([object2 valueForKeyPath:[self key]])) {
return NSOrderedAscending;
}
return [super compareObject:[(Saga*)object1 title] toObject:[(Saga*)object2 title]];
}
@end
3) Sort by Volume Numbering IF it is part of a Saga, otherwise, sort by Book Title. Here is my problem, as I don't know what key to send and what to put in my descriptor (I'm not even sure it's possible).
NSSortDescriptor* thirdSort = [[SagaTomaisonOrBookTitleSortDescriptor alloc] initWithKey:@"self" ascending:YES];
So far, I've found that @"self" allows to send the object being queried but it doesn't seem to allow queries of parameters inside the sent object. For reference, there is some code I tried:
- (NSComparisonResult)compareObject:(id)object1 toObject:(id)object2
{
if (NULL_OBJECT([(Book*)object1 fromSaga]) && NULL_OBJECT([(Book*)object2 fromSaga])) {
return [super compareObject:[(Book*)object1 title] toObject:[(Book*)object2 title]];
}
if (NULL_OBJECT([(Book*)object1 fromSaga])) {
return NSOrderedDescending;
}
if (NULL_OBJECT([(Book*)object2 fromSaga])) {
return NSOrderedAscending;
}
return [super compareObject:[(Book*)object1 tomaison] toObject:[(Book*)object1 tomaison]];
}
Any idea what I can and should do ?
Thanks !
EDIT: there was a type in the last line
回答1:
If you're not using an SQL-based store, you could do this by passing self as your key and compare: as the selector, then implement that custom selector. That is, make a method on your book class called compare: and just have it do all of your logic rather than using multiple sort descriptors.
来源:https://stackoverflow.com/questions/11182297/custom-nssortdescriptor-on-complex-object