0

非常に奇妙な問題が発生しています。数か月のテストの後、アプリを送信しようとしたときにたまたまポップアップしました。

JSONデータを取得して辞書に変換する次のメソッドがあります。

NSError *e;
NSMutableDictionary *result= [NSJSONSerialization JSONObjectWithData:jsonData 
                              options:NSJSONReadingMutableContainers error:&e];
if (e != nil) return nil;

過去数か月間、この方法はノンストップで使用されており、まったく問題はありません. しかし、ちょうど今日、それは機能しなくなりました。常にエラーが発生するようになりました (説明なし; 非 nil エラーのみ)。

問題を解決するために私がしなければならなかったのは、 set NSError *e = nil;. それを行うのは良い習慣であり、絶対に重要ではないと思いました。これは私を怖がらせます。自分のコードでこれを他に何回行っているのだろうか。何が起こっている可能性があるのか​​ 誰か説明できますか?

また、私は ARC を使用しているため、これが起こっていることがさらに奇妙になっていると思います。

4

3 に答える 3

4

コードが間違っているので、修正も間違っています。あなたがする必要があるのは言うことです

if (result == nil) {
    // an error occurred, and the NSError* variable can now be consulted
}

resultが 以外の場合、 の内容について何もnil推測することはできません。e


ここでの基本的な理由は、NSError**戻り値を持つ API は、API がエラーを返さない限り、その場所に何かを配置する必要がないからです。通常、これは、エラーでない場合、値をまったく変更しないことを意味します。そのため、e以前に変数にあったものは何でも、その後にあるものになります。コードが ARC なしでコンパイルされている場合、e変数にはスタックからのガベージが含まれます。ARC の下では に初期化されますがnil、後で説明する理由から、ARC の下にはいないと思います。

ただし、これよりも複雑です。メソッドがエラーを返さなくても、NSError**値が変更されている可能性があります。簡単な例は、このメソッドが別のメソッドを呼び出し、NSError**そのメソッドに同じメソッドを渡し、エラーから回復して代わりに成功値を返す場合です。しかし、2 番目の方法NSError*では、有効でなくなったエラーが変数に入力されている可能性があります。

さて、あなたのコードが ARC ではないと私が考える理由は、私の知る限りでは、最近のすべての Cocoa API は、エラーが発生しない限り値を変更しないように苦労しているからです。NSError**これは、1 年か 2 年前に確立された新しいガイドライン (2011 年か 2012 年の初めのどちらかでしたが、どちらかは忘れました) に沿ったものであり、NSError**パラメーターを持つメソッドはエラーの場合にのみパラメーターを変更する必要があります。これはNSError *e = nil; [foo callAPIWithError:e]; if (e) ...、実際には API のルールに従っていない場合でも、NSError正しくないコードに直面した場合の回復力を高めるための実用的な問題として、コードが機能することを許可することを目的としています。また、ARC はオブジェクト型のすべての自動変数をゼロにするため、クラッシュはそれeがゼロにされていないことを示しているため、ARC にいません。

ただし、上記の段落で述べたことにかかわらず、エラーがスローされない場合でも、有効なNSErrorAPI が値をそのままにしておくと想定しないでください。NSErrorこのような API を実装するための現在のガイドラインでは、それが正しいとされていますが、それは厳密な要件ではありません。これらのガイドラインの前に書かれたコードはそのように動作しない可能性があり、ガイドラインの後に書かれたコードはそれらを無視する可能性があります. 有効な APIを呼び出すための規則では、NSError引き続き API の戻り値を参照する必要がありNSError*、戻り値がエラーの発生を示している場合にのみ変数を確認することができます。

于 2012-12-12T19:37:08.533 に答える
2

エラーの理由を順を追って説明しましょう。

NSError *e; //some garbage non-nil value may be here

NSMutableDictionary *result= [NSJSONSerialization JSONObjectWithData:jsonData 
                              options:NSJSONReadingMutableContainers error:&e]; // no error, e is untouched, garbage is still here

if (e != nil) return nil; // there was no error but because of garbage we think there was one

したがって、最初に結果の値を確認するか、e 変数を nil に設定する必要があります (最初の値が優先されます)。

于 2012-12-12T19:38:10.937 に答える
0

そのメソッドのリファレンスには次のように書かれています。

戻り値 data 内の JSON データからの Foundation オブジェクト、またはエラーが発生した場合は nil。

そのため、戻り値を使用してエラーを検出し、詳細が必要な場合にのみエラー オブジェクトを確認します。

于 2012-12-12T19:37:15.207 に答える