像MPMediaPickerController / iPod库一样对NSArray进行排序

时间:2011-01-16 20:38:51

标签: iphone cocoa-touch sorting nsarray mpmediapickercontroller

我正在为iPhone开发一个自定义UIViewController,它为我的应用程序的本地文档目录中的文件模拟MPMediaPickerController的子集。特别是,我正在尝试重新创建“歌曲”选项卡。我已经成功创建了我的新控制器,除了我无法让歌曲标题像他们在iPod库或MPMediaPickerController中那样排序。以下是歌曲名称需要如何排序的示例:

  1. 很棒的歌曲标题
  2. 酷歌
  3. 史上最黑暗的歌曲
  4. 我的歌曲标题
  5. 真酷的歌
  6. 为什么选择我?
  7. 4小时浪费
  8. 正如您所看到的,排序排除了歌曲标题中的主要文章,并且还将以数字值开头的歌曲放在列表的末尾。任何人都可以建议一个有效的排序功能,将这些问题考虑在内吗?

2 个答案:

答案 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保持一致,所以你去吧。

最后一个难题是UILocalizedIndexedCollat​​ion类。这个方便的小助手类将帮助您对数据进行排序,以便通过UITableViewDataSource将其提供给UITableView。这里有一个关于如何将UILocalizedIndexedCollat​​ion类与模型结合使用的片段:

   // 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];
   }];

关于UILocalizedIndexedCollat​​ion的一个简短说明(来自Apple的文档):

  

如果应用程序提供了   Localizable.strings文件   目前的语言偏好,   indexed-collat​​ion对象本地化   方法返回的每个字符串   由选择器识别。

因此,请确保为要支持的每种语言提供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;
}