2009-05-24 4 views
44

このコンセプトは私を困らせるようです。なぜ、NSErrorオブジェクトはオブジェクトを変更しているメソッドに渡されたポインタを必要としますか?例えば、エラーへの参照を渡すだけで同じことはしないでしょうか? doStuffでなぜNSErrorは二重間接を必要としますか? (ポインタへのポインタ)

NSError *anError; 
[myObjc doStuff:withAnotherObj error:error]; 

、その後:

- (void)doStuff:(id)withAnotherObjc error:(NSError *)error 
{ 
    // something went bad! 
    [error doSomethingToTheObject]; 
} 

なぜ他のほとんどのオブジェクト・メッセージング・パターンのような上記の作業は動作しませんか?代わりに、エラー:(NSError **)エラーを使用する必要がありますか?

答えて

75

NSError**パターンは、メソッドが通常は値を返すときに使用されますが、失敗した場合はエラーオブジェクト(タイプNSError*)を返す必要がある場合があります。 Objective-Cでは、メソッドは1つのタイプのオブジェクトのみを返すことができますが、これは2つを返す場合です。 C言語のような言語では、余分な値を返す必要がある場合は、その型の値へのポインタを要求します。したがって、NSError*を返すには、NSError**パラメータが必要です。より現実的な例は、これを次のようになります。

// The method should return something, because otherwise it could just return 
// NSError* directly and the error argument wouldn't be necessary 
- (NSArray *)doStuffWithObject:(id)obj error:(NSError **)error 
{ 
    NSArray *result = ...; // Do some work that might fail 
    if (result != nil) { 
    return result; 
    } else { 
    // Something went bad! 
    // The caller might pass NULL for `error` if they don't care about 
    // the result, so check for NULL before dereferencing it 
    if (error != NULL) { 
     *error = [NSError errorWithDomain:...]; 
    } 
    return nil; // The caller knows to check error if I return nil 
    } 
} 

あなただけの代わりにNSError**NSError*パラメータ、その後doStuffは、呼び出し元に戻ってエラーオブジェクトを渡すことはできないだろうしていた場合。

6

代替声明n8grayが言った:

は、あなたがメッセージを送信するためのオブジェクトを受けていないので。オブジェクトを作成して返します。一度にreturnステートメントを使用できるのは、一度に1つのステートメントしか使用できないため、NOで既にそれを使用しているため、通常はポインタへのポインタNSError * - 可変引数が必要です。

+0

こんにちは、ピーター:-)私はあなたが新年のスタートを切ってくれることを願っています。 '**'について 'C 'をブラッシングしながら、私はこのポストにここに上陸しました。すみません、私はまだそれを取得していません:オブジェクトにポインタを1つだけ '*'渡した場合、オブジェクトに変更するだけで十分でしょうか?オブジェクトを変更するために、オブジェクトへのポインタへのポインタを渡す必要があるのはなぜですか?非常に前もってありがとう。よろしく。 – Unheilig

+3

@Unheilig: "もしオブジェクトにポインタを1つだけ渡したら、オブジェクトに変更を加えるだけで十分でしょうか?"そのオブジェクトにメッセージを送信するには、オブジェクトへのポインタが必要です。 "なぜオブジェクトに変更を加えるためにオブジェクトへのポインタへのポインタを渡す必要があるのでしょうか?"あなたはオブジェクトを変更していないので、新しいオブジェクトを作成して呼び出し元に返します。呼び出し元が指定したアドレスに割り当てることで、ポインタをオブジェクトに渡す変数へのポインタを指定します。 –

+0

+1。これもクリアしていただきありがとうございます。 – Unheilig

89

かなり単に:

あなたはあなたの関数にオブジェクトへのポインタを渡した場合、関数は、ポインタが指しているものを変更することができます。

オブジェクトへのポインタへのポインタを渡すと、その関数は別のオブジェクトを指すようにポインタを変更できます。

NSErrorの場合、関数は新しいNSErrorオブジェクトを作成し、そのNSErrorオブジェクトへのポインタを戻すことができます。したがって、ポインタを変更できるように二重間接が必要です。

+7

これは本当に私を理解するのに役立ちます。私は "byref"と "byval"の引数を区別する言語の文脈でポインタを考えるのに慣れています。 Byrefのargs(つまりポインタで参照される変数)は呼び出された関数で変更でき、呼び出し元は変更を見ることができるので、@ n8grayの答えは分かりませんでした: "あなたは' NSError * '...' doStuff'エラーオブジェクトをその呼び出し元に戻すことは決してできません "。あなたの答えは、 "関数がポインタを変更して別のオブジェクトを指すようにする"ことができます。 – stifin

6

古い質問が、それでも私はその価値がここにこれを入れて考える -

実際の犯人がNSErrorです。そのクラス参照を見ると、その属性(つまり、domain、code、またはuserInfo)のセッターメソッドはありません。したがって、方法はありません.NSEエラーを割り当てて初期化し、メソッドに渡して、渡されたNSErrorオブジェクトの情報を設定することができます。 (セッターメソッドがあれば、メソッドでerror.code = 1のようなものをNSError *に渡すことができました)

エラーが発生した場合、新しいNSErrorオブジェクトを生成する必要がありますあなたがそうしているのであれば、それを呼び出し元に戻す唯一の方法は、NSError **引数を持つことです。 (上記の答えで説明された理由のため)

0

私はまだすべての答えを読んで完全な画像を得ることができませんでした。私が下で行った平凡な練習は、最終的に何が起こっているのか理解するのを助けました。他の初心者に役立つように、そこに置いてください。

では、次の手順

ClassX *objectX = [[ClassX alloc] init]; 
NSMutableArray *arrayXX = [@[@(1), @(2)] mutableCopy]; 
//What is stored in arrayXX is the address in the heap at which the NSMutableArray object starts, lets call this address ZZZ 
//array starting at address ZZZ in the heap now contains NSNUmbers @1,@2 
[objectX methodX:array] 

あなたが[objectX methodX:array]を起動すると、どのような方法で受信されていることコピーであるを持っているあなたは、コードのいくつかの他の部分では

@interface Class X 
-(void) methodX:(NSMutableArray *)array; 
@end 

を以下していると仮定しますarray。配列にはアドレス(すなわちポインタ)が含まれているので、コピーは、受け取ったものがアドレスZZZを持つ別の変数であるという点で特別です。

したがって、methodXが[array removeObjectAtIndex:0]の場合、アドレスZZZから始まるオブジェクトは影響を受けます(現在は1つのNSNUmber @(2)しか含まれていません)。したがって、メソッドが返ってくると、元の配列も影響を受けます。

代わりにmethodXがarray = [@[@(2)] mutableCopy];であると仮定すると、元の配列は影響を受けません。これはあなたが住所ZZZに行って何かを変更しなかったからです。代わりに、のコピーにZZZを上書きして、別のアドレスYYYに送信しました。 YYYアドレスは、1つの要素NSNUmber @(2)を持つNSMUtableArrayオブジェクトの先頭です。元のZZZアドレスにはまだ2つの要素を持つNSMUtableArrayが含まれています。 @(1)と@(2)。したがって、メソッドが返るとき、元の配列は影響を受けません。

関連する問題