在 iPhone 顶级异常处理程序中显示警报

发布于 2024-08-12 08:56:42 字数 909 浏览 1 评论 0原文

我正在尝试在顶级 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)。有办法让这项工作发挥作用吗?

I'm trying to display a UIAlertView in a top-level iPhone exception handler. The handler function looks like this:

void applicationExceptionHandler(NSException *ex) {
  UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                      message:[ex reason]
                                                      delegate:nil
                                             cancelButtonTitle:@"OK"
                                             otherButtonTitles:nil];
  [alertView show];
}

I've seen similar code elsewhere (for instance, NSSetUncaughtExceptionHandler not catch all errors on iPhone).

If I single-step in the debugger, I can see that the exception handler is called, and I can see the current screen dim as if it's going to display the alert in front of it, but nothing appears. Outside of the debugger, the app just quits immediately and goes back to the system home screen.

It does work if I trap an error in applicationDidFinishLaunching and display an alert there before returning. I assume that the alert view never gets a chance to display in the exception handler because the app is terminating (as opposed to sitting there doing nothing if I just bail out of applicationDidFinishLaunching). Is there a way to make this work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小…楫夜泊 2024-08-19 08:56:42

非常感谢 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);

Thanks heaps to benzado, here's what I think is a great generic top-level exception handler. I'm a beginner so hopefully it's done properly, but it does work :)

In my ...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;
}

And in my ...appDelegate.h:

@interface ...appDelegate : NSObject <UIApplicationDelegate, UIAlertViewDelegate>
...
void exceptionHandler(NSException *exception);
ゞ花落谁相伴 2024-08-19 08:56:42

我不知道 [alertView show] 是如何实现的,但我想它会对视图层次结构进行一些更改,然后将其自身设置为在下一次通过运行循环时显示警报(看看上NSRunLoop)。

但是,由于应用程序即将退出,控制权不会返回到运行循环,因此永远不会显示警报。这就是为什么您会看到屏幕变暗(show 立即添加警报级别的 UIWindow),但警报却没有出现(这会在运行循环中发生)。

如果您在异常处理程序末尾包含 [[NSRunLoop currentRunLoop] run] ,则可能会出现警报。

如果你想让你的应用程序在警报完成后退出,你可以通过在 while 循环中调用 NSRunLoop 的 runUntilDate: 来实现,检查标志的值以查看警报是否已被执行。还被解雇了。如果有,只需退出处理函数即可。这意味着您必须在警报上设置一个委托对象来设置该标志。

如果你想让你的应用程序继续运行......我不太确定。您可以让运行循环继续运行异常处理程序,但这可能会产生不良/奇怪的副作用。所以你可能应该让应用程序退出。此外,如果您确定可以从异常中恢复,那么您应该在某个地方捕获它。

I don't know exactly how [alertView show] is implemented, but I imagine it makes some changes to the view hierarchy and then sets itself to display the alert on the next pass through the run loop (look up NSRunLoop).

But, since the app is about to quit, control doesn't return to the run loop, so the alert is never displayed. That's why you see the screen dim (the alert-level UIWindow is immediately added by show) but the alert doesn't appear (that would happen in the run loop).

If you include [[NSRunLoop currentRunLoop] run] at the end of your exception handler, the alert may appear.

If you want to let your app quit once the alert is done, you can probably do so by calling NSRunLoop's runUntilDate: in a while-loop, checking the value of a flag to see if the alert has been dismissed yet. If it has, simply exit the handler function and you're good to go. That means you'll have to set a delegate object on the alert which sets that flag.

If you want to let your app continue running... there I'm not so sure. You could just let the run loop continue to run out of the exception handler, but there might be bad/strange side effects to that. So you probably should let the app quit. Besides, if you're sure you can recover from the exception, you should have caught it somewhere.

下雨或天晴 2024-08-19 08:56:42

您应该验证代码是否已到达或者是否只是存在显示问题。

NSLog 会澄清这一点。

如果未达到,您需要防止应用程序关闭,并且您可能需要延迟操作才能脱离警报调用的上下文:

[self performSelector: @selector(showAlert:) withObject:@"msg" afterDelay: 0.1];

如果您达到了它并且执行上下文不是问题,但您根本没有看到警报,那么[警报显示] 可能不是显示的顶级。在这种情况下,您可能需要通过 showinview 重定向消息,例如使用操作表:

topDelegate=[[UIApplication sharedApplication] delegate];
topDelegateWindow=[topDelegate.window.subviews objectAtIndex:0];

[actionSheet showInView:topDelegateWindow];

You should verify if code is reached or if you just have display issue.

NSLog's will clarify that.

If not reached, you need to prevent app shutdown, and you may need a delayed action to get out of that context for the alert call:

[self performSelector: @selector(showAlert:) withObject:@"msg" afterDelay: 0.1];

If you are reaching it and execution context is not an issue but you simply are not seeing alert, then [alert show] may be not be top level in display. In such case, you may need to redirect message via showinview e.g. with actionsheet:

topDelegate=[[UIApplication sharedApplication] delegate];
topDelegateWindow=[topDelegate.window.subviews objectAtIndex:0];

[actionSheet showInView:topDelegateWindow];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文