3

iPhone の例外処理について、いくつか疑問があります。ここにそれらがあります:

  1. 次々に呼び出される一連のメソッドがあるとします。つまり、メソッド A がメソッド B を呼び出し、メソッド B がメソッド C を呼び出し、メソッド C がメソッド D を呼び出します。try-catch ブロックを配置するのに最適な場所はどれですか (方法 A か B か C か D か、またはそれらすべてか)。また、例外が発生したというアラートをユーザーに表示する必要があり、この例外をサーバーに記録したいと考えています。したがって、このすべてのメソッドで try - catch ブロックを記述していて、メソッド D; で例外が発生した場合。次に、アラートが4回表示され、ロギング用のWebサービスも4回呼び出されると思います(コントロールがメソッドAのブロックをキャッチするまで)。では、@throw; を使用するだけでよいでしょうか。メソッドB、C、DのcatchブロックでロジックをメソッドA(トップレベルメソッド)のcatchブロックに書くか、メソッドB、C、Dでtry - catchをまったく書かないようにする必要があります。

  2. 例外から何らかのエラー コードが必要です (Web サービスにはエラー コードと説明のパラメーターが必要なため)。例外をエラーに変換することは可能ですか、それともこのコードをハードコーディングする必要がありますか?

  3. NSSetUncaughtExceptionHandler についてどこかで読んだことがあります。そして、このハンドラーを (アプリ デリゲートの appDidFinishLaunching メソッドで) およびハンドラー メソッドで設定できれば、ユーザーにアラートを表示して Web サービスを呼び出すことができればと思います。次に、各クラスの各メソッドに try - catch ブロックを記述する必要はありません。私は正しいですか??

  4. 例外が発生し、try - catch ブロックまたは NSSetUncaughtExceptionHandler のいずれかを記述した場合、アプリは引き続き実行されますか、それともどのユーザー イベントにも応答しません。(クラッシュを処理すると確信しています。私が知りたいのは、ハングするかどうかです)

誰かがこの例外トピックについて教えてください。

4

1 に答える 1

19

0) Cocoa で例外を避ける。それらは通常、回復不可能です。独自のエラー報告のためにそれらをキャッチすることはできますが、通常、それらから回復できると想定するのは安全ではありません。

1) 捕まえる必要がある場合は、すぐに捕まえてください。独自のスローを記述しないでください。代わりに、のようなものに変換してNSError渡します。NSErrorローカライズされたメッセージだけでなく、エラー コードを表示または送信するために必要なすべての情報を含めることができます。

2) anNSExceptionを an にNSError(直接)変換することはできません。これは、 NSExceptionan が持つすべてのプロパティを持たないためNSErrorです。これは異なるデータ表現です。1 つは、エラー コードが利用できないことです。2 つ目は、説明がローカライズされていないことです。できる最善の方法は、エラー コードとドメインを作成し、必要なプロパティを から使用してNSExceptionに保存することNSErrorです。これは次のようになります。

// error checking omitted
extern NSString* const MONExceptionHandlerDomain;
extern const int MONNSExceptionEncounteredErrorCode;

NSError * NewNSErrorFromException(NSException * exc) {
    NSMutableDictionary * info = [NSMutableDictionary dictionary];
    [info setValue:exc.name forKey:@"MONExceptionName"];
    [info setValue:exc.reason forKey:@"MONExceptionReason"];
    [info setValue:exc.callStackReturnAddresses forKey:@"MONExceptionCallStackReturnAddresses"];
    [info setValue:exc.callStackSymbols forKey:@"MONExceptionCallStackSymbols"];
    [info setValue:exc.userInfo forKey:@"MONExceptionUserInfo"];

    return [[NSError alloc] initWithDomain:MONExceptionHandlerDomain code:MONNSExceptionEncounteredErrorCode userInfo:info];
}

@catch (NSException * exc) {
    NSError * err = NewNSErrorFromException(exc);
    ...
}

使用する API が、キャッチして回復することが期待される例外をスローする場合 (たとえば、真に例外的なケースではない場合)、はい、キャッチして続行を試みることができます。残念ながら、Cocoa で例外をキャッチするつもりで例外を作成する人は、確実なアンワインド実装を実装するのに十分なほど問題を理解していない可能性があります (たとえば、リークが発生したとしても、それは確実ではありません)。

3) アラートを表示する時間や場所ではありません。最上位の例外ハンドラを ( 経由でNSSetUncaughtExceptionHandler) インストールする場合 - メッセージをログに記録する必要があります - すると、例外ハンドラは中止されます。アプリは不安定な状態にあります。続行することは中止することよりも悪いことです。これらのカスタム メッセージをホームに送信することをお勧めします。アプリの次回の起動時に送信することをお勧めします。

4) ほとんどの場合、アプリは不安定な状態にあるため、続行しないでください。しかし、これらのコーナーケースについて実際に答えるには:問題が例外的ではなく (例: ファイルが見つからない)、ベンダーが本当に続行することを期待している場合、実際には (100% 安全ではない) 場合でも、ベンダーは続行することを期待していると想定する必要があります。". 最上位の例外ハンドラ内から回復/継続しようとしないでください (プログラムは復帰後に中止されます)。非常に凝っていて、すぐに OSX に表示したい場合は、別のプロセスが最適です。純粋な C++ インターフェイスを介して呼び出している場合、巻き戻しは明確に定義されており、キャッチする必要があります - 回復可能な場合は続行してください。C++ の例外は回復可能であり、明確に定義されています。また、非常に広範囲に使用されています (例外的な条件よりも少ない条件を含む)。

(IMO...) ObjC の例外は導入されるべきではなく、システムまたはサードパーティのライブラリからスローするメソッドは非推奨にする必要があります。彼らはうまく、または明確に定義された方法でリラックスしません。同様に、通常の Cocoa プログラム フローに対してアンワインド フローが実行されます。つまり、スローの時点で変化していて、スローとキャッチの間にある objc オブジェクトのメモリ/リレーションに触れることは、未定義の動作と同じくらい良いことを意味します。問題は、そのメモリが何であるかわからないことです(ほとんどの場合、妥当なメンテナンス時間内に)。C++ 例外は明確に定義されており、正しくアンワインドされます (たとえば、デストラクタが呼び出されます) - しかし、ObjC コンテキストで続行しようとすると、未定義の動作の結果が無視されます。IMO、それらは ObjC++ にのみ存在する必要があります (C++ には必要なため)。

理想的な世界では、使用する ObjC プログラムとライブラリは (まったく) 例外を使用しません。スローするライブラリ (Cocoa を含む) を使用しているため、エラーに関する特別な情報が必要な場合にのみ、トップ レベルの例外ハンドラをインストールしてください。API が、制御できない状況により例外がスローされることを期待でき、回復が期待される場合、キャッチを記述しますが、すぐにそのロジックを通常のプログラム フローに変換します (例: NSError)。独自のスローを記述する必要はありません。-[NSArray objectAtIndex:および「オブジェクトがセレクターに応答しない」は、プログラマーのエラーの例です。これらはキャッチされるべきではありませんが、プログラムを修正する必要があります。

于 2011-12-06T08:33:19.443 に答える