2012年08月08日

NSStringでパス文字列を比較する場合

前回はNSURLについて書いたが、今回も同じようなパス名の話。

まだローカルディスク上のファイルなどを指定する場合に、NSURLで記述していなくてNSStringを使っている場合も多い。

あるフォルダと同じフォルダを指定した場合には処理をスキップするようなコードを書いたのだが、その時にはまったこと。

文字列が一致するかどうかの比較をする場合には -isEqualToString: または compare: を使うが、パス文字列の場合には注意しないといけないことがある。

例えば、「/Users/eien/Documents」というフォルダは最後に/がある「/Users/eien/Documents/」も同じパスとして認識してほしいのだが文字列としては一致していない。

このため、パス名として表記を統一するためのメソッドがあってそれが -stringByStandardizingPath だ。これで正規化した文字列同士で先のメソッドを使って比較すればいいことになる。

もちろんディレクトリに限らずファイルであっても同じ。またパス文字列は「/Users/eien/tmp/../Documents」や「/Users/eien/Documents/.」なども同じフォルダを指すことになりこれも同じパスとして比較できるようにもなる。


#import <Foundation/Foundation.h>

int main(int argc,char *argv[]){
id ap = [[NSAutoreleasePool alloc] init];
NSString *path1 = @"/Users/eien/tmp";
NSString *path2 = @"/Users/eien/tmp/";
if ( [path1 compare:path2] == NSOrderedSame ) {
NSLog(@"Same!, %@ == %@",path1,path2);
} else {
NSLog(@"differnt, %@ != %@",path1,path2);
}
path1 = [path1 stringByStandardizingPath];
path2 = [path2 stringByStandardizingPath];
if ( [path1 compare:path2] == NSOrderedSame ) {
NSLog(@"Same!, %@ == %@",path1,path2);
} else {
NSLog(@"differnt, %@ != %@",path1,path2);
}
[ap drain];

return 0;
}


ここではcompareを使っているが、 -isEqualToString:でももちろんよい。
タグ:NSString
posted by 永遠製作所 at 01:23| 東京 ☁| Comment(0) | TrackBack(0) | Cocoa | このブログの読者になる | 更新情報をチェックする

2012年08月03日

NSURLをNSStringから作る時に失敗した

NSURLは随分前からあるし何をするものかわかりきっているのだけど、うっかりミスで長時間原因究明に時間がかかってしまったので念のためメモを残しておくことにする。

アップルは最近ローカルディスク上のファイルアクセスにもNSStringを使ったパスではなくNSURLを使う使うことを推奨しており、過去に...WithPath:などのパスでファイルを指定するAPIを...WIthURL:のようにNSURLを使うAPIに変更し古いAPIはdeprecatedにしつつある。

しかも今回OSをMountain Lionにアップグレードした直後だったので自分の使い方ではなくてOSのバグを疑ってしまったので解決までに時間がかかってしまった。

問題はパス文字列からNSURLを作るとき、あるいはNSURLからパス文字列に変換するときに使うメソッドの選択である。

例えば、 /Users/name/Documents/Readme.txt というファイルパスに対するパス文字列は以下で作成できる。


NSString *aPath = @"/Users/name/Documents/Readme.txt";


そして、これの中身をバイナリデータとして取り込むには以下で可能だ。

NSData *aData = [NSData dataWithContentsOfFile:aPath];


同じNSDataを取り出すのにURLを使うこともできて以下のようになる。

NSData *aData = [NSData dataWithContentsOfURL:aURL];


ここでaURLをどうやって作るかを間違えた。

NSURL *aURL = [NSURL URLFromString:aString];


これでもエラーにはならないので平気だと思って使ってしまった。実際に使ったのはNSPathControlだが、実際なんの問題も起らないでほとんど使える。上記で作ったURLをセットしてもフォルダアイコンがカスタムのものにならない程度でほぼ使えている。ところがその子要素であるNSPathComponentCellからURLを取り出そうとするとこれがセットされていなかったというわけだ。

使うべきAPIはこちら。

NSURL *aURL = [NSURL fileURLWithPath:aString];


逆にNSURLからパス文字列を取り出すには

NSString *thePath = [aURL path];


でよい。これは上記で失敗したからpathという単純なのではだめだからきっとabsolutePathの方だと思ってしまいやっぱり失敗した。
posted by 永遠製作所 at 00:19| 東京 ☀| Comment(0) | TrackBack(0) | Cocoa | このブログの読者になる | 更新情報をチェックする

2012年07月22日

NSIndexPathの文字列化


Cocoaのフレームワークの中には簡単な構造体を文字列に変換するのに便利な関数が用意されている。NSLog()などで印字する際に%@では変換できないのでそれを簡易にできるいわばデバッグ用なんだろうと思う。

NSStringFromCGRect, NSStringFromCGPoint, NSStringFromCGSize (NSStringFromNSRect, NSStringFromNSPoint, NSStringFromNSPoint)やNSStringRomRangeがそれ。

だが、NSIndexPathとかよく使う割にそういうのが用意されていない。Objective-Cクラスなので、descriptionメッセージに文字列を返すのでそれで十分ってことなんだろうけど、アドレス情報があったりしてちょっと見にくい。

なので代わりになるメソッドを作ってみた。デバッグ用ということで実効効率はあまり考慮していないが使ってみて欲しい。

ついでに文字列からオブジェクトを作る方も用意した。

section = 1, row = 5なら"1.5"とか{ 1, 5, 6, 4 }なら "1.5.6.4"とかの結果になる。

NSIndexSetもついでにと思ったが、そっちはあまり使っていないので、まあ今度必要になったら作ろうと思う。

@interface NSIndexPath (String)

- (NSString*)stringValue;
+ (NSIndexPath*)indexPathFromString:(NSString*)aString;

@end

@implementation NSIndexPath (String)

- (NSString*)stringValue
{
NSMutableArray *anArray = [NSMutableArray arrayWithCapacity:self.length];
for (NSUInteger pos = 0; pos < self.length; pos++) {
NSUInteger index = [self indexAtPosition:pos];
[anArray addObject:[NSNumber numberWithUnsignedInteger:index]];
}
return [anArray componentsJoinedByString:@"."];
}

+ (NSIndexPath*)indexPathFromString:(NSString*)aString
{
NSArray *anArray = [aString componentsSeparatedByString:@"."];
NSIndexPath *indexPath = [[NSIndexPath alloc] init];
for (NSString *aComponent in anArray) {
NSUInteger index = [aComponent integerValue];
indexPath = [indexPath indexPathByAddingIndex:index];
}
return indexPath;
}

@end

// (C) 2012 Eien Factory


ARC利用前提の実装です。

一応MITライセンスにしますが、改変再配布商用利用自由。
posted by 永遠製作所 at 22:33| 東京 ☔| Comment(0) | TrackBack(0) | Cocoa | このブログの読者になる | 更新情報をチェックする

2011年09月13日

[書籍]詳解 Objective-C 2.0 改訂版



ようやくこの本を読みました。最初の版から何度も読み返しています。が、2.0改訂版が出た後はすぐに購入したのに、ちょっとずつしか読む時間が取れず通して読み終わるのが今頃になってしまいました。

内容の素晴らしさはまったく変わっていません。

Mac/iOS開発者が本格開発を始める前に読んでおくべき必須書。改訂版では10.5/iOS4向けの新機能ブロック、GCDなども加え。基本の基本から重要なイディオムなども含む記述は以前からものを踏襲。分厚さに負けそうになってもあきらめないで。読了後のプログラミング能力は読み始める前に比べて格段に進歩しているはず。バグが少なく効率的で保守性の高いコーディングができるようになるためのバイブル。

というわけで過去の版との比較です。と思ったんですが、2.0の版だけ手元に見当たりません。これだけ買わなかったのかなぁ?
続きを読む
posted by 永遠製作所 at 21:31| 東京 ☀| Comment(0) | TrackBack(0) | Cocoa | このブログの読者になる | 更新情報をチェックする

2011年09月11日

NSStringとC文字列(4)

シリーズ4回目。前3回はNSStringからC文字列を取り出す方法について。今回はその逆C文字列からNSStringを作る方法。こっちはややこしいことはなく割と素直にできる。


+ (id)stringWithCString:(const char *) cString encoding:(NSStringEncoding) enc


クラスメソッドを使ってNULL終端されたC文字列からC文字列のエンコーディングを指定してNSStringを生成。C文字列のエンコーディングを指定するのであって、指定されたエンコーディングで内部保持されるわけではないので。為念。

C文字列の文字列エンコーディングがUTF8の時だけ専用のメソッドがあって以下;

+ (id)stringWithUTF8String:(const char *) bytes

続きを読む
posted by 永遠製作所 at 14:08| 東京 ☁| Comment(0) | TrackBack(0) | Cocoa | このブログの読者になる | 更新情報をチェックする