質問

iPhoneでの例外処理に関していくつか疑問があります。ここにあります:

  1. 次々と呼ばれているメソッドのチェーン、つまりメソッドA呼び出し方法Bを持っているとします。メソッドaまたはbまたはcまたはd、またはそれらのすべてです)。また、例外が発生したことをユーザーにアラートを表示する必要があります。その後、この例外をサーバーにログに記録したいと思います。したがって、私が私の試みを書いている場合 - このすべての方法でブロックをキャッチし、方法Dで例外が発生した場合。次に、アラートが4回表示され、ロギング用のWebサービスも4回呼び出されます(方法Aのブロックをキャッチするためにコントロールが到達するまで)。したがって、 @スローを使用する必要があります。メソッドB、C、Dのキャッチブロックで、メソッドA(トップレベルの方法)のキャッチブロックで私のロジックを書きます。

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

  3. nssetuncaughtexceptionhandlerについてどこかで読んでいました。そして、このハンドラーを(AppDidfinishlaunching App Delegateの方法で)設定して、ハンドラー方法で、ユーザーにアラートを表示してWebサービスに電話することができると思います。その後、私は試してみる必要はありません - 私の各メソッドで、各クラスでブロックをキャッチします。私は正しいですか?

  4. 例外が発生し、TRY -CATCHブロックまたはNSSetunCaughtExceptionHandlerのいずれかを書き込んだ場合、アプリは実行され続けるか、ユーザーイベントのいずれにも応答しません。 (私はそれがクラッシュを処理すると確信しています。私が知りたいのは、それがぶら下がっているかどうかです)

誰かがこの例外トピックについて私を啓発してください。

役に立ちましたか?

解決

0)ココアの例外を避けてください。それらは一般的に回復不能です。あなたはあなた自身のエラー報告のためにそれらをキャッチするかもしれませんが、あなたがそれらから回復できると仮定するのは一般に安全ではありません。

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

2)変換することはできません NSExceptionNSError (直接)and NSException すべてのプロパティを持っているわけではありません NSError 持っている - それは別のデータ表現です。 1つは、エラーコードが利用できないことです。 2つ目は、説明がローカライズされていません。あなたができる最善のことは、エラーコードとドメインを作成し、から必要なプロパティを使用することです。 NSException そしてそれをanに保存します 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が、キャッチして回復することが期待される例外をスローする場合(たとえば、本当に例外的なケースではありません)、はい、キャッチして続行しようとすることができます。残念ながら、ココアに例外を書く人は、おそらく堅実な巻き上げ実装を実装するのに十分な問題を十分に理解していない可能性があります(たとえば、漏れを生成しても、堅実ではありません)。

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

4)ほとんどの場合、アプリは不安定な状態にあり、続行しないでください。しかし、実際にそれらのコーナーケースに答えるために:「はい、キャッチしたときに回復して継続することができますが、スローAPIが回復がサポートされていると述べている場合にのみ回復して継続する必要があります。問題がコントロールを超えている場合、そして、問題は例外的ではなく(例:ファイルが見つかりません)、ベンダーは本当にあなたが継続することを期待しているので、実際には(100%安全ではない)にもかかわらず、彼らはあなたが継続することを期待していると仮定する必要があります。」トップレベルの例外ハンドラー内から回復/継続しようとしないでください(プログラムは返された後に中止されます)。あなたが非常に派手になり、OSXですぐにそれを提示したいなら、別のプロセスが最適です。純粋なC ++インターフェイスを通じて呼び出している場合、巻き戻しは明確に定義されており、キャッチする必要が必要です - 回復可能な場合は続けてください。 C ++の例外は、回復可能であり、明確に定義される可能性があります。また、非常に広範囲に使用されています(例外的な条件未満を含む)。

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top