Поскольку, похоже, никто не может предложить решение, я решил опубликовать решение, которое придумал. Сначала я создал модель для своих данных:
@interface MyModel : NSObject
{
NSString* _value;
NSString* _sortableValue;
}
@property (nonatomic,copy) NSString* value;
- (NSString*)sortableValue;
- (NSString*)comparableString:(NSString*)str;
@end
Ключом к модели является метод сопоставимого типа, который используется для создания sortableValue. Вот реализация модели:
@implementation MyModel
@synthesize value=_value;
-(void)dealloc
{
[_value release];
[_sortableValue release];
[super dealloc];
}
- (void)setValue:(NSString*)value
{
[_value release];
_value = [value copy];
[_sortableValue release];
_sortableTValue = nil;
}
- (NSString*)sortableValue
{
if (_sortableValue == nil)
_sortableValue = [[self comparableString:_value] retain];
return _sortableValue;
}
- (NSString*)comparableString:(NSString*)str
{
if (str == nil)
return nil;
else if ([str length] == 0)
return [NSString stringWithString:str];
NSCharacterSet* numbersSet = [NSCharacterSet decimalDigitCharacterSet];
if ([str rangeOfCharacterFromSet:numbersSet options:0 range:NSMakeRange(0, 1)].location != NSNotFound)
return [NSString stringWithString:str];
NSRange range = NSMakeRange(0, [str length]);
if ([str compare:@"a " options:(NSAnchoredSearch|NSCaseInsensitiveSearch) range:NSMakeRange(0, 2)] == NSOrderedSame)
range.location = 2;
else if ([str compare:@"an " options:(NSAnchoredSearch|NSCaseInsensitiveSearch) range:NSMakeRange(0, 3)] == NSOrderedSame)
range.location = 3;
else if ([str compare:@"the " options:(NSAnchoredSearch|NSCaseInsensitiveSearch) range:NSMakeRange(0, 4)] == NSOrderedSame)
range.location = 4;
range.length -= range.location;
NSCharacterSet* lettersSet = [NSCharacterSet letterCharacterSet];
NSUInteger letterOffset = [str rangeOfCharacterFromSet:lettersSet options:0 range:range].location;
if (letterOffset == NSNotFound)
return [NSString stringWithString:str];
letterOffset -= range.location;
range.location += letterOffset;
range.length -= letterOffset;
return [str substringWithRange:range];
}
@end
Помимо удаления лидирующих статей из строки, также удаляются все лидирующие не буквенные символы. В моей библиотеке iPod есть песня под названием «$ ell Your $ oul», которая заканчивается в разделе E в MPMediaPickerController. Я не уверен, что это было бы то, что я сделал бы, если бы я написал первоначальный алгоритм сортировки, но я собирался согласовать его с MPMediaPickerController, так что вы идете.
Последняя часть головоломки - класс UILocalizedIndexedCollation. Этот удобный маленький вспомогательный класс поможет вам отсортировать данные, чтобы упростить их передачу в UITableView через UITableViewDataSource. Вот фрагмент о том, как использовать класс UILocalizedIndexedCollation вместе с моделью:
// tableData will contain an NSArray for each populated section in the table view
NSMutableDictionary* tableData = [NSMutableDictionary dictionary];
NSMutableArray* myArray = [NSMutableArray array];
// Populate myArray with instances of MyModel
UILocalizedIndexedCollation* indexer = [UILocalizedIndexedCollation currentCollation];
for (MyModel* data in myArray)
{
NSInteger index = [indexer sectionForObject:data collationStringSelector:@selector(sortableValue)];
NSNumber* key = [[NSNumber alloc] initWithInteger:index];
NSMutableArray* array = [tableData objectForKey:key];
if (array == nil)
{
array = [NSMutableArray new]; // Will be released after creating a sorted array in the following section
[tableData setObject:array forKey:key];
}
[array addObject:data];
[key release];
}
[tableData enumerateKeysAndObjectsUsingBlock:^(id key, id array, BOOL* stop)
{
NSMutableArray* sortedArray = [[indexer sortedArrayFromArray:array collationStringSelector:@selector(sortableValue)] mutableCopy];
[tableData setObject:sortedArray forKey:key];
[array release];
}];
Одна быстрая заметка о UILocalizedIndexedCollation (из документации Apple):
Если приложение предоставляет
Файл Localizable.strings для
текущие языковые предпочтения,
объект индексированного сопоставления локализуется
каждая строка возвращается методом
идентифицируется селектором.
Поэтому убедитесь, что вы предоставили строки Localizable.string для каждого языка, который хотите поддерживать, иначе в табличном представлении будут только разделы A-Z и #.
Мне потребовалось время, чтобы проработать все детали этого, поэтому я надеюсь, что это станет полезным для других людей. Если вы видите какие-либо способы, которыми я могу улучшить это, пожалуйста, дайте мне знать!