我正在为iPhone开发一个自定义UIViewController,它为我的应用程序的本地文档目录中的文件模拟MPMediaPickerController的子集。特别是,我正在尝试重新创建“歌曲”选项卡。我已经成功创建了我的新控制器,除了我无法让歌曲标题像他们在iPod库或MPMediaPickerController中那样排序。以下是歌曲名称需要如何排序的示例:
正如您所看到的,排序排除了歌曲标题中的主要文章,并且还将以数字值开头的歌曲放在列表的末尾。任何人都可以建议一个有效的排序功能,将这些问题考虑在内吗?
答案 0 :(得分:4)
由于看起来没有人可以提供解决方案,我想我会发布我想出的解决方案。首先,我为我的数据创建了一个模型:
@interface MyModel : NSObject
{
NSString* _value;
NSString* _sortableValue;
}
@property (nonatomic,copy) NSString* value;
- (NSString*)sortableValue;
- (NSString*)comparableString:(NSString*)str;
@end
它们对模型的关键是equivalentString方法,它用于创建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”的歌曲,最终出现在MPMediaPickerController的E部分。我不确定这是我在创建初始排序算法时会做的事情,但我会与MPMediaPickerController保持一致,所以你去吧。
最后一个难题是UILocalizedIndexedCollation类。这个方便的小助手类将帮助您对数据进行排序,以便通过UITableViewDataSource将其提供给UITableView。这里有一个关于如何将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文件 目前的语言偏好, indexed-collation对象本地化 方法返回的每个字符串 由选择器识别。
因此,请确保为要支持的每种语言提供Localizable.strings,否则您的表格视图将只包含A-Z和#。
部分。我花了一段时间才弄清楚这方面的所有细节,所以我希望它对其他人有用。如果您发现任何可以改进的方法,请告诉我们!
答案 1 :(得分:-2)
您可能需要考虑带有重音的某些字符,例如è,é,ò,à,ù,ì。
所以我稍微修改了你的代码以包含它。您的代码对我们所有的iphone开发人员都有很大的贡献
- (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;
//my modification starts here.........
NSString * finalString = [str substringWithRange:range];
NSString * firstCharString = [finalString substringToIndex:1];
NSData * encodedData = [firstCharString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString * encodedString = [[NSString alloc] initWithBytes:[encodedData bytes] length:[encodedData length] encoding:NSASCIIStringEncoding];
if ([encodedString isEqualToString:@"?"]) {
return finalString;
}
NSString * finalProcessedString = [finalString stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:encodedString];
[encodedString release];
return finalProcessedString;
}