2

アプリケーションのローカル ドキュメント ディレクトリにあるファイルの MPMediaPickerController のサブセットをエミュレートする iPhone 用のカスタム UIViewController を開発しています。特に、Songs タブを再作成しようとしています。iPod Library や MPMediaPickerController のように曲のタイトルを並べ替えることはできませんが、新しいコントローラーの作成には成功しています。曲名をソートする必要がある例を次に示します。

  1. 素晴らしい曲のタイトル
  2. かっこいい歌
  3. 史上最も暗い歌
  4. 私の曲のタイトル
  5. 本当にクールな曲
  6. なんでわたし?
  7. 4時間の無駄

ご覧のとおり、並べ替えによって曲のタイトルの先頭の記事が除外され、数値で始まる曲はリストの最後に配置されます。これらのチュールを考慮した効率的なソート機能を提案できる人はいますか?

4

2 に答える 2

4

誰も解決策を提供できないように見えるので、思いついた解決策を投稿しようと思いました。まず、データのモデルを作成しました。

@interface MyModel : NSObject
{
   NSString* _value;
   NSString* _sortableValue;
}

@property (nonatomic,copy) NSString* value;

- (NSString*)sortableValue;
- (NSString*)comparableString:(NSString*)str;

@end

モデルの鍵となるのは、sortableValue の作成に使用される comparisonString メソッドです。モデルの実装は次のとおりです。

@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 ファイルを提供する場合、インデックス付き照合オブジェクトは、selector によって識別されるメソッドによって返される各文字列をローカライズします。

そのため、サポートする言語ごとに 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 に答える