4

G. Lee による Test-Driven iOS development という本を読んでいて、この単体テストに出くわしましたが、理解できません。まず、さらにコードが必要な場合は、すぐにお知らせください。

-(void)testDelegateNotifiedOfErrorWhenNewsBuilderFails
{
    MockNewsBuilder *builder = [MockNewsBuilder new];
    builder.arrayToReturn = nil;
    builder.errorToSet = underlyingError;
    newsManager.newsBuilder = builder;
    [newsManager receivedNewsJSON:@"Fake Json"];
    ...
}

-(void)receivedNewsJSON:(NSString *)objectNotation
{
    NSError *error = nil;
    //  As you see error is nil and I am passing in a nil error.
    NSArray *news = [_newsBuilder newsFromJSON:objectNotation error:&error];
    ...
}

@implementation MockNewsBuilder

-(NSArray *)newsFromJSON:(NSString *)objectNotation error:(NSError **)error
{
    // But once I arrive here, error is no longer nil.
    // (NSError **) error = 0x00007fff5cb887f0 domain: @"Fake Json" - code: 0
    ...
}

エラーはどのように自動的に設定されますか?

アップデート:

皆様、活発な議論とアドバイスをありがとうございました。答えは、&のために呼び出し側がエラーインスタンスを取得する方法を説明しています。私はそれを明確に理解しています。nil である必要があるにもかかわらず、呼び出し側が入力された NSError インスタンスを指している理由について、私の疑問は残ります。内部にエラー インスタンスを設定していないのにnewsFromJSON:error:、どのようにそこに既に入力されているのでしょうか?

変更したばかり[newsManager receivedNewsJSON:@"Fake Json1"];で、内のエラー インスタンスがすぐにnewsFromJSON:error:反映され (NSError **) error = 0x00007fff5b9b27f0 domain: @"Fake Json1" - code: 0ます。その非常に紛らわしい...

4

3 に答える 3

3

これは、ポインターの概念への単なるポインターです。参照エラー オブジェクト &error への参照をメソッドに渡しています-(NSArray *)newsFromJSON:(NSString *)objectNotation error:(NSError **)error;

これにより、渡したメモリ ポインタのエラー オブジェクトが更新されます。

これがポインターへのポインターの概念であることを確認してください。

ここに画像の説明を入力

アップデート:

あなたのエラーオブジェクトはゼロです、はい、その権利です。ただし、そのエラー オブジェクトをメソッドに渡すのではなく、エラー オブジェクトnewsFromJSONのメモリ アドレスを渡します( &error)。これは、エラー オブジェクトのメモリ アドレスです。これが、メソッド
内で null 以外の値を取得している理由です。newsFromJSON

もう 1 つ、次のように operator( operator)newsFromJSONの内容を使用して、メソッド内の元のオブジェクトにアクセスできます。***error = something;

これにより、呼び出し元メソッドNSError *errorで宣言した元のオブジェクト ( ) が更新されます。 C、CPP、または Objective-C では、& は演算子のアドレス、* は演算子の内容です。

&obj -> obj のメモリ アドレスを指定します
*obj -> obj 内のメモリ アドレスの内容を指定します。

于 2014-12-18T10:02:52.693 に答える
0

errortype の変数NSError*、つまり「NSError へのポインタ」です (objective-C では、たとえば C++ とは対照的に、すべてのオブジェクトが参照として扱われます)。

これが意味することはerror、実際のNSErrorオブジェクトのアドレスを格納する (ローカル) 変数、initialnilです。

呼び出すメソッドは、(自動解放された)NSErrorインスタンスを作成します。そのインスタンスへの参照を戻すには、メソッドにポインタのアドレス、または を渡す必要があります&error。これは、「ポインタからポインタへのポインタ」型ですNSError(2 レベルの間接参照に注意してください)。

これを行うのは、C の関数と Objective-C のメソッドへの引数が値で渡されるためです。単に を渡しerrorた場合、そこに格納されている値 ( nil) だけがコピーされ、呼び出されたメソッドが何を行っても、変数の内容errorはあなたの側 (発信者) は変更できません。これを実現するには、エラーのアドレスを渡す必要があります&error

このようにして、呼び出されたメソッドは (そこに保持されているアドレス) の内容を「変更」しerrorて、新しく作成されたNSErrorインスタンスを指すようにすることができます。

それは理にかなっていますか?

補遺:これは、Cocoa でよく見られる非常に一般的なパターンです: 呼び出されるメソッドが失敗する可能性があり、戻り値を使用して成功/失敗を通知する代わりに、詳細なエラーを取得するために追加の「in/out」パラメーターが渡されます。失敗した場合の情報。失敗すると、メソッドはfalse( NO、など) を返すことができますが、さらに、インスタンス 0内でより詳細なエラー レポート (失敗の理由など) を提供することもできます。NSError

EDITED: @Droppyが言ったように、関連するすべてのコードがあなた自身のものである(つまり、ファーストパーティまたはサードパーティのフレームワークではない)ことを確認すると、明示的にどこかに割り当てない限り、errorそれ以外に設定することは不可能です. nilおそらく、デバッガーで「監視」して、いつ/どこで設定されているかを確認する必要があります。メッセージが に設定されているように見えるため@"Fake JSON"、最初にできることは、プロジェクト (すべてのファイル) でその文字列を検索することです。

于 2014-12-18T10:10:51.197 に答える
0

** はポインタへのポインタです。これは、関数またはメソッドにポインタ アドレスを渡す必要があることを意味します。Objective-C は C の厳密なスーパーセットです。つまり、C と同様に、関数とメソッドは 1 つの値しか返すことができません。それには2つの方法があります。1 つは、すべての戻り値を構造体または NSDictionaries またはその他のコレクションにラップすることです。この方法をoutParameterと呼び、inにポインタアドレスを渡しています。Cはバイコピー言語です。しかし、ポインターは移植可能なブラック ホールであり、C でワイルドなことを行うことができます。Objective-C と C++ は、同じワイルドさを提供します。

エラーは、Apple のフレームワーク コードによって設定されます。通常、Cocoa のパターンは、BOOL を返し、NSError ポインター アドレスを渡すことです。BOOL が NO の場合、NSError をチェックします。Apple フレームワークは、NSError ポインター アドレス ボックスにいくつかのプレゼントを置きます。

BOOL を使用せず、代わりにオブジェクトまたは nil を返すことがあります。

Core Foundation C フレームワークは非常によく似た働きをし、in および out パラメータを多く使用します。

于 2014-12-18T10:12:12.080 に答える