Iphone 对NSArray(如MPMediaPickerController/iPod库)进行排序

Iphone 对NSArray(如MPMediaPickerController/iPod库)进行排序,iphone,cocoa-touch,sorting,nsarray,mpmediapickercontroller,Iphone,Cocoa Touch,Sorting,Nsarray,Mpmediapickercontroller,我正在为iPhone开发一个自定义UIViewController,它模拟我的应用程序的本地文档目录中的文件的MPMediaPickerController的子集。特别是,我正在尝试重新创建“歌曲”选项卡。我已经成功地创建了我的新控制器,只是我不能像iPod库或MPMediaPickerController中那样对歌曲标题进行排序。以下是歌曲名称需要如何排序的示例: 真棒的歌名 酷歌 有史以来最黑暗的歌曲 我的歌名 一首很酷的歌 为什么是我 浪费4小时 如您所见,排序排除了歌曲标题中的前导文章,

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

  • 真棒的歌名
  • 酷歌
  • 有史以来最黑暗的歌曲
  • 我的歌名
  • 一首很酷的歌
  • 为什么是我
  • 浪费4小时

  • 如您所见,排序排除了歌曲标题中的前导文章,并将以数值开头的歌曲放在列表的末尾。有人能建议一个有效的排序功能,将这些tules考虑在内吗?

    既然看起来没有人能提供解决方案,我想我会发布我提出的解决方案。首先,我为我的数据创建了一个模型:

    @interface MyModel : NSObject
    {
       NSString* _value;
       NSString* _sortableValue;
    }
    
    @property (nonatomic,copy) NSString* value;
    
    - (NSString*)sortableValue;
    - (NSString*)comparableString:(NSString*)str;
    
    @end
    
    模型的关键是comparableString方法,该方法用于创建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
    
       // 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];
       }];
    
    除了从字符串中删除前导项目外,它还删除所有前导非字母字符。我的iPod库中有一首歌名为“$ell Your$oul”,它最终出现在MPMediaPickerController的E部分。我不确定如果我把最初的排序算法装箱,我会做什么,但我要与MPMediaPickerController保持一致,所以你就这样做了

    拼图的最后一块是UILocalizedIndexedCollation类。这个方便的小助手类将帮助您对数据进行排序,使通过UITableViewDataSource向UITableView提供数据变得轻而易举。下面是一个关于如何将UILocalizedIndexedCollation类与模型结合使用的片段:

    @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
    
       // 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的一个简要说明(来自苹果的文档):

    如果应用程序提供 的Localizable.strings文件 当前的语言偏好 索引排序规则对象本地化 方法返回的每个字符串 由选择器标识

    因此,请确保为要支持的每种语言提供一个Localizable.strings,否则您的表视图将只包含a-Z和#部分


    我花了一段时间才弄清楚这方面的所有细节,所以我希望它对其他人有用。如果你看到我可以改进的方法,请告诉我

    >P>你可能需要考虑某些带有重音的字符,例如,艾,欧,,,,,, 因此,我稍微修改了您的代码以合并此。您的代码对我们所有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;
    }
    

    +一个伟大的工人。我见过你的问题一次,但我没有时间找到解决办法。干得好,回答得真棒。您能否建议我如何使用
    MPMediaQuery
    实现此功能?我如何将其包括在
    UITableViewController
    类中,我是否需要为节创建一个单独的包含字母列表的数组?这由UILocalizedIndexedCollation在调用SortedArray FromArray:collationStringSelector:时自动处理,从我提供的最后一个代码片段开始。此外,您的添加只考虑第一个字符,如果字符串中的其他字符有重音符号,则会产生意外的结果。