iPhone のトップレベルの例外ハンドラーでアラートを表示する
-
21-09-2019 - |
質問
最上位の iPhone 例外ハンドラーで UIAlertView を表示しようとしています。ハンドラー関数は次のようになります。
void applicationExceptionHandler(NSException *ex) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
message:[ex reason]
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
}
他の場所でも同様のコードを見たことがあります (たとえば、 NSSetUncaughtExceptionHandler が iPhone のすべてのエラーをキャッチしない).
デバッガーをシングルステップで実行すると、例外ハンドラーが呼び出されていることがわかり、目の前にアラートが表示されるかのように現在の画面が薄暗くなっているのが見えますが、何も表示されません。デバッガーの外では、アプリはすぐに終了し、システムのホーム画面に戻ります。
applicationDidFinishLaunching でエラーをトラップし、戻る前にそこにアラートを表示すると機能します。アプリが終了しているため、例外ハンドラーでアラート ビューが表示される機会がないと仮定します (applicationDidFinishLaunching から救済するだけで何もせずにそこに座っているのとは対照的です)。これを機能させる方法はありますか?
解決
正確にはわかりません [alertView show]
が実装されていますが、ビュー階層にいくつかの変更を加えて、実行ループの次のパスでアラートを表示するように自分自身を設定すると思います(調べてください) NSRunLoop
).
ただし、アプリが終了しようとしているため、制御が実行ループに戻らないため、アラートは表示されません。画面が暗く見えるのはこのためです (アラート レベルの UIWindow はすぐに追加されます) show
)しかし、アラートは表示されません(実行ループで発生します)。
含める場合 [[NSRunLoop currentRunLoop] run]
例外ハンドラーの最後にアラートが表示される場合があります。
アラートが完了したらアプリを終了させたい場合は、おそらく NSRunLoop のメソッドを呼び出すことで実行できます。 runUntilDate:
while ループでフラグの値をチェックして、アラートがまだ解除されているかどうかを確認します。すでに存在している場合は、ハンドラー関数を終了するだけで準備完了です。つまり、そのフラグを設定するアラートにデリゲート オブジェクトを設定する必要があります。
アプリを実行し続けたい場合は...そこはよくわかりません。実行ループを例外ハンドラーから実行し続けることもできますが、それによって悪い/奇妙な副作用が発生する可能性があります。したがって、おそらくアプリを終了させたほうがよいでしょう。さらに、例外から確実に回復できるのであれば、どこかで例外をキャッチしているはずです。
他のヒント
ヒープがbenzadoおかげで、ここで私は偉大なジェネリックトップレベルの例外ハンドラと思われるものです。私はそれが適切に行われていますので、できれば初心者だが、それは作業を行います。)
で私の... appDelegate.mます:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[window makeKeyAndVisible];
NSSetUncaughtExceptionHandler(&exceptionHandler);
return YES;
}
BOOL exceptionAlertDismissed = FALSE;
void exceptionHandler(NSException *exception)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"App Committed Suicide"
message:@"Oh dear, that wasn't supposed to happen. You will have to restart the application... sorry!"
delegate:[[UIApplication sharedApplication] delegate] cancelButtonTitle:nil otherButtonTitles:@"That's ok!", @"Erm, bye...", nil];
[alert show];
[alert release];
while (exceptionAlertDismissed == FALSE)
{
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
exceptionAlertDismissed = TRUE;
}
そして、私の... appDelegate.hで
@interface ...appDelegate : NSObject <UIApplicationDelegate, UIAlertViewDelegate>
...
void exceptionHandler(NSException *exception);
コードに達した場合や、単に表示上の問題がある場合は、確認する必要があります。
のNSLogのはそれを明確にします。
達していない場合は、、あなたはアプリのシャットダウンを防ぐために必要がある、とアラートコールにその文脈から抜け出すために遅延作用を必要とする場合があります:
[self performSelector: @selector(showAlert:) withObject:@"msg" afterDelay: 0.1];
あなたはそれに達していると実行コンテキストが問題ではないですが、あなたは、単に警告が表示されない場合は、は、その後、[警告を表示]は、ディスプレイのトップレベルではないことがあります。このような場合、あなたは経由showinview例えばメッセージをリダイレクトする必要があるかもしれませんactionsheet付きます:
topDelegate=[[UIApplication sharedApplication] delegate];
topDelegateWindow=[topDelegate.window.subviews objectAtIndex:0];
[actionSheet showInView:topDelegateWindow];