blog:2013:2013-02-16

差分

このページの2つのバージョン間の差分を表示します。

この比較画面にリンクする

blog:2013:2013-02-16 [2013-02-16 23:16]
Decomo 作成
blog:2013:2013-02-16 [2015-01-06 11:51]
行 1: 行 1:
-====== NSArrayをFinder風の並び順でソートする ====== 
  
-こんなファイルがあったとする。 
- 
-  file-a 
-  file-1 
-  file-01 
-  file-2 
-  file-10 
-  file-b 
-  file-ab 
- 
-辞書式で並べ替えると 
- 
-  file-01 
-  file-1 
-  file-10 
-  file-2 
-  file-a 
-  file-ab 
-  file-b 
- 
-となるわけだが、Finderでソートすると 
- 
-  file-1 
-  file-01 
-  file-2 
-  file-10 
-  file-a 
-  file-ab 
-  file-b 
- 
-となる。連続した数字部分を数値と見なし、数値順で並べてくれる。個人的にはこの方が分かりやすくて好きだ。 
- 
-で、この数値順ソートをCocoaで実現するにはどーしたらいいのかなー?と思って調べていたら、[[http://developer.apple.com/library/mac/#qa/qa1159/|Technical Q&A QA1159: Sorting Like the Finder]]という、そのまんまの記事がADCにあった。流石林檎様、分かっていらっしゃる。 
- 
-上記Q&Aのコードを改造して<ilcode>NSMutableArray</ilcode>のカテゴリメソッドにするとスマートに使えて良い感じ。 
- 
-<ilcode>NSString</ilcode>配列のソートはもちろん、任意のオブジェクトの場合はソートに使う<ilcode>NSString</ilcode>インスタンス変数名を<ilcode>sortByFinderOrderWithStringObjectKey:</ilcode>に渡せばおk。 
- 
-<code objc> 
-#include <CoreServices/CoreServices.h> 
-#include <sys/param.h> 
- 
-static CFComparisonResult CompareLikeTheFinder(const void *val1, const void *val2, void *context) 
-{ 
-    SInt32          compareResult; 
-    CFStringRef     lhsStr; 
-    CFStringRef     rhsStr; 
-    CFIndex         lhsLen; 
-    CFIndex         rhsLen; 
-    UniChar         lhsBuf[MAXPATHLEN]; 
-    UniChar         rhsBuf[MAXPATHLEN]; 
- 
-    // val1 is the left-hand side CFString. 
-    // val2 is the right-hand side CFString. 
-    if (context) 
-    { 
-        NSString *key = (NSString *)context; 
-        lhsStr = (CFStringRef)[(NSObject *)val1 valueForKey:key]; 
-        rhsStr = (CFStringRef)[(NSObject *)val2 valueForKey:key]; 
-    } 
-    else 
-    { 
-        lhsStr = (CFStringRef)val1; 
-        rhsStr = (CFStringRef)val2; 
-    } 
-    lhsLen = CFStringGetLength(lhsStr); 
-    rhsLen = CFStringGetLength(rhsStr); 
- 
-    // Get the actual Unicode characters (UTF-16) for each string. 
-    CFStringGetCharacters(lhsStr, CFRangeMake(0, lhsLen), lhsBuf); 
-    CFStringGetCharacters(rhsStr, CFRangeMake(0, rhsLen), rhsBuf); 
- 
-    // Do the comparison. 
-    UCCompareTextDefault( 
-                         kUCCollateComposeInsensitiveMask 
-                         | kUCCollateWidthInsensitiveMask 
-                         | kUCCollateCaseInsensitiveMask 
-                         | kUCCollateDigitsOverrideMask 
-                         | kUCCollateDigitsAsNumberMask 
-                         | kUCCollatePunctuationSignificantMask, 
-                         lhsBuf, 
-                         lhsLen, 
-                         rhsBuf, 
-                         rhsLen, 
-                         NULL, 
-                         &compareResult 
-                         ); 
- 
-    // Return the result. Conveniently, UCCompareTextDefault  
-    // returns -1, 0, or +1, which matches the values for  
-    // CFComparisonResult exactly. 
-    return (CFComparisonResult)compareResult; 
-} 
- 
-static void SortCFMutableArrayLikeTheFinder(CFMutableArrayRef array, CFStringRef key) 
-{ 
-    CFArraySortValues( 
-                      array,  
-                      CFRangeMake(0, CFArrayGetCount(array)), 
-                      CompareLikeTheFinder, 
-                      key 
-                      ); 
-} 
- 
-@interface NSMutableArray (PKAdditions) 
-- (void)sortByFinderOrder; 
-- (void)sortByFinderOrderWithStringObjectKey:(NSString *)key; 
-@end 
- 
-@implementation NSMutableArray (PKAdditions) 
-- (void)sortByFinderOrder 
-{ 
-    [self sortByFinderOrderWithStringObjectKey:nil]; 
-} 
- 
-- (void)sortByFinderOrderWithStringObjectKey:(NSString *)key 
-{ 
-    SortCFMutableArrayLikeTheFinder(self, key); 
-} 
-@end 
-</code> 
- 
-実際のファイル名やディレクトリ名をソートする場合は、<ilcode>- [NSFileManager displayNameAtPath:(NSString *)path]</ilcode>で得られる名前をソートしないとFinder順にはならなかったりする。 
  • blog/2013/2013-02-16.txt
  • 最終更新: 2015-01-06 11:51
  • (外部編集)