Пользовательская сортировка с NSFetchedResultController (подкласс NSSortDescriptor) - PullRequest
6 голосов
/ 05 ноября 2010

Я хочу предоставить пользовательскую сортировку с использованием NSFetchedResultsController и NSSortDescriptor.

Как пользовательская сортировка с помощью сообщения NSSortDescriptor - (id) initWithKey: ascending: selector: невозможна (см. здесь ),Я попытался использовать производный класс NSSortDescriptor, чтобы переопределить compareObject: toObject: message.

Моя проблема заключается в том, что compareObject: toObject: не всегда вызывается.Кажется, он вызывается только тогда, когда данные уже находятся в памяти.Существует некоторая оптимизация, которая использует сортировку на основе базы данных вместо CompareObject: toObject, когда данные извлекаются из хранилища в первый раз.(см. здесь ).

Мой вопрос таков: как заставить NSFetchedResultscontroller использовать сообщение compareObject: toObject: для сортировки данных?(и будет ли он работать с большим набором данных)

Одним из решений является использование двоичного хранилища вместо хранилища sqlite, но я не хочу этого делать.

Другое решение:
-call executeFetch для сортировки данных через SQL (CompareObject не вызывается)
-создать изменение данных и обратить их обратно.
-Call executeFetch еще раз (вызывается CompareObject)
Это работает в моем случаено это взлом, и я не уверен, что он всегда будет работать (особенно с большим набором данных (больше, чем размер пакета)).

ОБНОВЛЕНО: Вы можете воспроизвести с образцом CoreDataBooks.
В RootViewController.m добавьте этот уродливый хак:

- (void)viewWillAppear:(BOOL)animated {
    Book* book = (Book *)[NSEntityDescription insertNewObjectForEntityForName:@"Book" 
                 inManagedObjectContext:[self fetchedResultsController].managedObjectContext];
    [[self fetchedResultsController] performFetch:nil];
    [[self fetchedResultsController].managedObjectContext deleteObject:book];
    [self.tableView reloadData];
}

В RootViewController.m замените код дескриптора сортировки на:

MySortDescriptor *myDescriptor = [[MySortDescriptor alloc] init];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:myDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];  

Добавьте класс MySortDescriptor:

@implementation MySortDescriptor

-(id)init
{
    if (self = [super initWithKey:@"title" ascending:YES selector:@selector(compare:)])
    {

    }
    return self;
}

- (NSComparisonResult)compareObject:(id)object1 toObject:(id)object2
{
    //set a breakpoint here
    return [[object1 valueForKey:@"author" ] localizedCaseInsensitiveCompare:[object2 valueForKey:@"author" ] ];
}

//various overrides inspired by [this blog post][3]
- (id)copy
{
    return [self copyWithZone:nil ];
}
- (id)mutableCopy
{
    return [self copyWithZone:nil ];
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
    return [self copyWithZone:zone ];
}
- (id)copyWithZone:(NSZone*)zone
{
    return [[MySortDescriptor alloc] initWithKey:[self key] ascending:[self ascending] selector:[self selector]];
}
- (id)reversedSortDescriptor
{
    return [[[MySortDescriptor alloc] initWithKey:[self key] ascending:![self ascending] selector:[self selector]] autorelease];
}
@end

1 Ответ

6 голосов
/ 10 ноября 2010

Применительно к вашему вопросу и комментариям.Вам нужно будет вытянуть объекты в память, чтобы отсортировать их.Как только они находятся в памяти, вы можете использовать удобный метод, чтобы определить расстояние от точки.

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

...