NSErrorは初期化してから使いましょう(なにをいまさら)

in

ライブラリのテストケースを書いているのですが、あるテストケースが必ずエラーになるので悩んでいたのですが昨日ようやく判明しました。ケースは渡したNSErrorがnilであること(テスト対象メソッドがエラーを戻さないこと)をテストしているんですが、なんのことはないNSErrorを初期化していなかったためでした。

どこで読んだのか(あるいは勘違いなのか)"Objective-Cでは変数は宣言した時点でnilで初期化される"みたいな思い込みがあって全然気がつきませんでした。気になってアップルのError Handling Programming Guide For Cocoaを読んでみたら、

NSError *theError;
BOOL success = [myDoc writeToURL:[self docURL]
                    ofType:@”html”
                    error:&theError];
if (success == NO) {
    // maybe try to determine cause of error and recover first
    NSAlert *theAlert = [NSAlert alertWithError:theError];
    [theAlert runModal]; // ignore return value
}

というサンプルや

NSError *theError;
NSData *theData = [doc dataOfType:@”xml” error:&theError];
if (!theData && theError)
    [anyView presentError:theError
            modalForWindow:[doc windowForSheet]
            delegate:self
            didPresentSelector:
                @selector(didPresentErrorWithRecovery:contextInfo:)
            contextInfo:nil];

など、必ずしもtheErrorを初期化していません。初期化しない場合上記コードのように戻り値を同時に判定する処理が必要になりますね。直接theErrorを判定するようなコードの場合はやっぱりnilで初期化されていました。

NSError* theError = nil;
[obj:&error];
if (theError)
{
:
}

僕は、C/C++で変数を宣言する場合だったら

char aString[256];
memset(aString,0x00,sizeof(aString));

と、不要に思えても初期化するタイプなんですが(これに異論がある人もいるようですね)、Objective-Cでは大抵の場合、宣言と生成が同時になされるような書き方をすることが断然多いからか(言い訳くさい)こういうことは不要だと思い込んでいました。それで今回の場合のように、戻り値を確認しないでいきなり

NSError *theError;
NSData *theData = [doc dataOfType:@”xml” error:&theError];
STAssertNil(theError,@"must nil");

みたいなケースを書いてしまったものだから迷う羽目になったわけです。ということはですよ、これまで書いたコードもこういう実装をしている可能性大ってことですよねぇ。あぁ、恐ろしい(あるいはエラーなんてロクにチェックしていないとか)。

この記事のトラックバックURL:

http://hippos-lab.com/blog/trackback/290

返信