Так что, борясь с этим слишком долго, без большого количества документации, я решил поделиться своим опытом с теми немногими, кто даже новее, чем я.
Вероятно, есть более чистые способы достижения того, что я сделал, поэтому, пожалуйста, не стесняйтесь предлагать улучшения.
Вот что я хотел сделать:
У меня есть NSArrayController, который управляет NSManagedObjects (скажем, Thing). Эти объекты имеют свойство name, которое имеет тип NSString.
Я хотел отсортировать массив контроллера массива, используя имя управляемых объектов. Обычный способ сортировки изменяемого массива строк должен выглядеть примерно так:
[myMutableArrayOfStrings sortUsingSelector:@selector(caseInsensitiveCompare:)];
или
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];
NSArray *descriptorArray = [NSArray arrayWithObject:sortDescriptor];
[myArrayController setSortDescriptors:descriptorArray];
Однако, если имена оказались числами, caseInsensitiveCompare: отсортирует 11 перед 8 (например).
Кроме того, я хотел, чтобы имя a11b сортировалось ПОСЛЕ a8b, а это означало, что мне нужно было разбивать имена управляемых объектов на группы из цифровых и нецифровых символов, а затем сравнивать их по отдельности.
Я придумал создать категорию NSString.
заголовочный файл:
#import <Foundation/Foundation.h>
@interface NSString (MyString)
- (NSComparisonResult)myCustomCompare:(NSString *)anotherString;
@end
файл реализации:
#import "MyString.h"
@implementation NSString (MyString)
- (NSComparisonResult)myCustomCompare:(NSString *)anotherString {
elaborate chopping up of strings into substrings..
For each of the 2 strings I made an NSMutableArray.
Then I determined if these substrings were NSNumbers, which have their own compare:, or NSStrings (caseInsensitiveCompare:)
Then I return an NSComparisonResult (NSOrderedAscending, NSOrderedSame or NSOrderedDescending)
}
@end
Затем в файле реализации моего Thing ManagedObject я переопределил
- (NSComparisonResult)compare:(Thing *)anotherThing {
return [self.name myCustomCompare:anotherThing.name];
}
Также необходимо импортировать MyString.h в класс Thing.
Теперь, используя
[[myArrayController arrangedObjects] sortUsingSelector:@selector(compare:)];
работает как шарм.
Только одна вещь, которая беспокоила меня. Если свойство имени Thing будет содержать десятичные числа, как, например, a1.4b и a1.39b, как я смогу изолировать их от имени? (a1.4b будет неправильно отсортирован до a1.39b)
Что еще хуже, пользователь может ввести имя вещи как 1.3.55 ...