0) Cocoa で例外を避ける。それらは通常、回復不可能です。独自のエラー報告のためにそれらをキャッチすることはできますが、通常、それらから回復できると想定するのは安全ではありません。
1) 捕まえる必要がある場合は、すぐに捕まえてください。独自のスローを記述しないでください。代わりに、のようなものに変換してNSError
渡します。NSError
ローカライズされたメッセージだけでなく、エラー コードを表示または送信するために必要なすべての情報を含めることができます。
2) anNSException
を an にNSError
(直接)変換することはできません。これは、 NSException
an が持つすべてのプロパティを持たないため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:
および「オブジェクトがセレクターに応答しない」は、プログラマーのエラーの例です。これらはキャッチされるべきではありませんが、プログラムを修正する必要があります。