2011-01-16 10 views
2

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

  1. 恐ろしい曲名が
  2. クールソング
  3. ダーケスト・ソングエヴァー
  4. マイ曲名
  5. 本当にクールな歌
  6. なんでわたし?あなたが見ることができるよう
  7. 4時間

を無駄にし、ソートは曲のタイトルでも有数の記事を除外しても、リストの末尾に数値で始まる曲を配置します。誰もがこれらのルールを考慮に入れた効率的なソート機能を提案できますか?

答えて

4

誰も解決策を提示できないようだから、思いついた解決策を投稿すると思った。まず、私は私のデータのためのモデルを作成しました:

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

@property (nonatomic,copy) NSString* value; 

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

@end 

彼らのモデルの鍵はsortableValueを作成するために使用されますcomparableString方法、です。

@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クラスの使用方法の抜粋です:(Appleのドキュメントから)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]; 
    }]; 

一つの簡単なメモ:

アプリケーションが のLocalizable.stringsファイルを提供している場合 現在の言語設定の場合、 インデックス付き照合オブジェクトは、 メソッドによって返された各文字列をセレクタによって識別された によってローカライズします。

したがって、サポートする言語ごとにLocalizable.stringsを指定する必要があります。そうしないと、テーブルビューにセクションA-Zと#のみが表示されます。

これについての詳細をすべて解説するにはしばらく時間がかかりました。だから、他の人にとって役に立つと思っています。私がこれを改善できる方法があれば、教えてください!

+1

+1素晴らしい仕事の男。私は一度ウルクを見たことがありますが、解決策を見つけ出す時間はありません。よくやった。 – KingofBliss

+0

恐ろしい答え。おそらく、私は 'MPMediaQuery'でこれを実装する方法を提案できますか?これを 'UITableViewController'クラスにどのように含めると、セクションの文字のリストで別の配列を作る必要がありますか? – sooper

-2

è、é、ò、à、à、ù、ìなどのアクセント付きの特定の文字も考慮する必要があります。

私はこれを組み込むようにコードを少し修正しました。あなたのコードは私たち全員に大きな貢献をしています。

- (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; 
} 
+1

これは、私が提供した最後のスニペットからsortedArrayFromArray:collat​​ionStringSelector:を呼び出すときに、UILocalizedIndexedCollat​​ionによって自動的に処理されます。また、文字列の他の文字にアクセント記号が付いていた場合に予期しない結果が生じる最初の文字のみを考慮に入れます。 –

関連する問題