Сортировка изменений положения основных данных с помощью дескрипторов сортировки для iPhone

У меня есть объект CoreData с двумя атрибутами. Один называется «позиция», другой называется «positionChange». Оба они являются целыми числами, где атрибут position — текущая позиция, а positionChange — разница между предыдущей позицией и новой позицией. Это означает, что positionChange может быть отрицательным.

Теперь я хотел бы отсортировать по positionChange. Но я бы хотел, чтобы он игнорировал отрицательные значения. В настоящее время я сортирую его по убыванию, что даст результат: 2, 1, 0, -1, -2. Но я ищу, чтобы получить этот результат: 2, -2, 1, -1, 0.

Любые идеи о том, как решить эту проблему с помощью дескрипторов сортировки?


РЕДАКТИРОВАТЬ

У меня есть 2 класса, один называется DataManager, а другой содержит мою категорию NSNumber (positionChange имеет тип NSNumber).

В DataManager у меня есть метод fetchData:, где я выполняю свой запрос на выборку с дескриптором сортировки:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Entity" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"positionChange" ascending:NO selector:@selector(comparePositionChange:)];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

Я делаю еще кое-что по запросу, но это не интересно для этой проблемы.

Моя категория NSNumber должна быть точно такой же, как та, которую вы разместили: В .h:

@interface NSNumber (AbsoluteValueSort)
- (NSComparisonResult)comparePositionChange:(NSNumber *)otherNumber;
@end

И в .м:

@implementation NSNumber (AbsoluteValueSort)

- (NSComparisonResult)comparePositionChange:(NSNumber *)otherNumber
{
    return [[NSNumber numberWithFloat:fabs([self floatValue])] compare:[NSNumber numberWithFloat:fabs([otherNumber floatValue])]];
}

@end

Когда я вызываю fetchData для своего объекта DataManager, я получаю эту ошибку:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'unsupported NSSortDescriptor selector: comparePositionChange:'

Есть идеи, в чем может быть дело? Я включил файл заголовка категории NSNumber в свой класс DataManager.


person Anonymous    schedule 30.06.2011    source источник
comment
Можете ли вы добавить в модель поле absolutePositionChange и заполнить его (в сеттере для positionChange, если он есть) значением abs(positionChange)? Вы можете использовать это поле в своем дескрипторе сортировки.   -  person Simon Whitaker    schedule 30.06.2011


Ответы (2)


Попробуйте это, предполагая, что ваше positionChange является NSNumber:

@interface NSNumber (AbsoluteValueSort)

-(NSComparisonResult) comparePositionChange:(NSNumber *)otherNumber;

@end

с последующим:

@implementation NSNumber (AbsoluteValueSort)

-(NSComparisonResult) comparePositionChange:(NSNumber *)otherNumber
{
    return [[NSNumber numberWithFloat: fabs([self floatValue])] compare:[NSNumber numberWithFloat: fabs([otherNumber floatValue])]];
}

@end

а затем сделайте это:

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"positionChange" ascending:NO selector:@selector(comparePositionChange:)];

и сортировать по этому дескриптору. Если вы хотите сделать так, чтобы -2 всегда было после 2 или 5 всегда после -5, вы можете изменить comparePositionChange: чтобы возвращать NSOrderedAscending в случаях, когда одно число является отрицательным для другого.

person med200    schedule 30.06.2011
comment
Можно ли вызвать метод категории между объектами? Я имею в виду, что мой дескриптор сортировки находится в классе, отличном от категории NSNumber. Вызов comparePositionChange: с вашим примером выше не будет работать. Вы понимаете мою точку зрения? - person Anonymous; 30.06.2011
comment
Просто включите в него любой файл с категорией NSNumber, и он должен работать. Категория не входит ни в один класс. - person med200; 30.06.2011
comment
Категория находится в классе NSNumber. Вызов его в вашем примере будет означать, что категория реализована в классе NSSortDescriptor. В противном случае приложение упадет с NSInvalidArgumentException по причине: «неподдерживаемый селектор». Простое включение в этом случае не сработает. Если только я не делаю что-то не так. Вы тестировали свое решение? - person Anonymous; 30.06.2011
comment
Я использовал дескриптор сортировки для сортировки уже заполненного массива объектов в .m-файле с категорией в его .h-файле. Это сработало. В документации для sortDescriptorWithKey:ascending:selector: говорится, что селектор должен указывать метод, реализуемый значением свойства, идентифицированного keyPath. Поэтому он ожидает метод, реализованный NSNumber, а не NSSortDescriptor. - person med200; 30.06.2011
comment
Эй, я отредактировал свой вопрос. Не разрешалось публиковать такой длинный пост или публиковать новый ответ. Не могли бы вы посмотреть и посмотреть, можете ли вы найти какие-либо ошибки? Спасибо! - person Anonymous; 30.06.2011
comment
У меня такая же ошибка. Я предполагаю, что вы не можете использовать настраиваемые селекторы для сортировки постоянных данных напрямую. Вам придется сортировать после того, как вы получите данные - я неправильно предположил, что оба способа будут работать. - person med200; 30.06.2011
comment
Прохладно. Теперь я заработал, сортируя массив результатов вместо запроса на выборку. Большое спасибо за твою помощь! - person Anonymous; 30.06.2011

Причина сбоя кода с ошибкой unsupported NSSortDescriptor selector заключается в том, что вы используете хранилище данных SQLite и пытаетесь использовать метод Cocoa в качестве дескриптора сортировки. В хранилище SQLite дескрипторы сортировки на лету транслируются в SQL, а сортировка выполняется SQLite. Это действительно повышает производительность, но это также означает, что сортировка выполняется в среде, отличной от Cocoa, где не существует вашего пользовательского метода сравнения. Подобная сортировка работает только для общеизвестных методов, а не для произвольного кода Cocoa.

Простым решением было бы выполнить выборку без сортировки, получить массив результатов и отсортировать его. Массивы можно сортировать с помощью любых методов Cocoa, которые вы хотите, поэтому категория med200 должна быть здесь полезной.

Вы также можете перейти от хранилища данных SQLite к двоичному хранилищу, если ваш набор данных не очень велик.

person Tom Harrington    schedule 30.06.2011