开发者

How can I do a case insensitive sort of NSFetchedResultsController that also ignores words like "the"?

I'm working on a Core Data driven app that has 2 entities requiring special sorting considerations in the NSFetchedResultsController.

The simpler case of the 2 just requires ignoring "The" so that (& I'm citing real data examples) The Planting Festival follows Peats Ridge Festival in the sort order. As a safety I'd also like to make that sort case insensitive. For that one I tried the suggestions here How can I sort an NSTableColumn of NSStrings ignoring "The " and "A "? by adding...

@property (nonatomic, readonly) NSString * sortname;

to the interface of my entity definition class &...

- (NSString *)sortname
{
    NSMutableString *temp = [NSMutableString stringWithString:[[self name] lowercaseString]];
    if ([temp hasPrefix:@"the "]) {
        return [temp substringFromIndex:4];
    }
    return temp;
}

to the implementation but the app crashes when I give it @"sortname" as the key for the NSSortDescriptor.

The 2nd entity is more complicated. In addition to stripping "The" for sorting there is also "A" & honorifics like "Dr" & "Professor" but not always. An example in data is Professor Ian Lowe & Professor Wallace's Puppet Theatre. Ian Lowe is a real person who (much as I respect him) should be sorted under I for Ian but there is no Professor Wallace, that's just the name on a, well, puppet theatre & it should be sorted under P. For that selective aspect of it I see no way other than having a boolean attribute on the entity specifies whether or not to strip the 1st word for sorting purposes.

For the rest of it the question comes down to... Is there a way to create a (for want of knowing a more correct term) virtual attribute on a Core Data entity that will work when I pass its name as the key for an NSSortDescriptor of an NSFetchedResultsController?

The desperate approach, which I'd rather not take, would be to create real sortname attributes on those 2 entities & calculate the values as I populate the entities.

Update... Attempting to follow TechZen's answer this is the constructor for my NSFetchedResultsController...

- (NSFetchedResultsController *)frc
{
    if (_frc) return _frc;

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"EventProfile"
                                              inManagedObjectContext:_moc];
    [request setEntity:entity];
    NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"name"
                                                           ascending:YES
                                   开发者_运维问答                       comparator:^NSComparisonResult(id obj1, id obj2) {
        NSMutableString *sortname1 = [NSMutableString stringWithString:[obj1 lowercaseString]];
        if ([sortname1 hasPrefix:@"the "]) {
            sortname1 = [NSMutableString stringWithString:[sortname1 substringFromIndex:4]];
        }
        NSMutableString *sortname2 = [NSMutableString stringWithString:[obj2 lowercaseString]];
        if ([sortname2 hasPrefix:@"the "]) {
            sortname2 = [NSMutableString stringWithString:[sortname2 substringFromIndex:4]];
        }
        return [sortname1 compare:sortname2];
    }];

    [request setSortDescriptors:[NSArray arrayWithObject:sorter]];
    [sorter release], sorter = nil;
    [request setFetchBatchSize:15];

    NSFetchedResultsController *frcTemp = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                              managedObjectContext:_moc
                                                                                sectionNameKeyPath:nil
                                                                                         cacheName:[NSString GetUUID]];
    [self setFrc:frcTemp];
    [_frc setDelegate:self];
    [frcTemp release], frcTemp = nil;
    [request release], request = nil;

    if ([[_frc fetchedObjects] count] == 0) {
        //<#statements#>
    }

    return _frc;
}

However it is still sorting by name. I inserted an "I'm here." log line in the comparator block & that didn't appear in my logs leading me to think the comparator isn't even being executed.

Cheers & TIA, Pedro :)


NSSortDescriptor does not accept transient property. But there is a work around.

In NSFetchedResultsController

set "sectionNameKeyPath" as your filter, and keep the NSSortDescriptor as the real column found in your core data. So your code would be:

NSFetchedResultsController *fetcher = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                                                  managedObjectContext:context
                                                                    sectionNameKeyPath:@"sortname" 
                                                                             cacheName:nil];


You probably want to use a sort descriptor with a block or selector (function) e.g.

+[NSSortDescriptor sortDescriptorWithKey:ascending:comparator:]

With a block or selector, you can create as complex and customized a sort as you need.

You can also use multiple sorts in the same fetch request just remember that the sorts are evaluated in array sequence.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜