2

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

  1. 好听的歌名
  2. 炫酷的歌
  3. 有史以来最黑暗的歌曲
  4. 我的歌名
  5. 一首很酷的歌
  6. 为什么是我?
  7. 浪费了 4 小时

如您所见,排序排除了歌曲标题中的主要文章,并将以数值开头的歌曲放在列表末尾。任何人都可以提出一个有效的排序函数来考虑这些 tules 吗?

4

2 回答 2

4

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

@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”的歌曲,它位于 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 文件,则索引排序对象将本地化由选择器标识的方法返回的每个字符串。

因此,请确保为要支持的每种语言提供 Localizable.strings,否则您的表格视图将只有 AZ 和 # 部分。

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

于 2011-02-15T05:15:11.860 回答
-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;
}
于 2011-02-19T00:46:50.460 回答