0

我想在应用关闭之前显示玻璃破碎动画。我设法通过设置 ExceptionHandler 在应用程序关闭之前捕获屏幕截图

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); 
    return YES;
}

void uncaughtExceptionHandler(NSException *exception) {

    UIWindow *lastWindow = [[UIApplication sharedApplication].windows lastObject];
    UIGraphicsBeginImageContext(lastWindow.bounds.size);
    [lastWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *pngImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData * data = UIImagePNGRepresentation(pngImage);
}

但是后来我什至无法在视图中添加一个简单的图像,应用程序在下一个绘图周期之前崩溃。应用程序关闭之前是否可以在屏幕上显示任何内容?

4

2 回答 2

3

一旦你触发了一个异常,你的应用程序的状态是未定义的;没有人知道你的应用程序正在做什么,虽然有很多事情可能出错(参见上面的链接),但我将在这里重点关注的是数据损坏。

一些崩溃报告者试图在程序终止后立即通过网络提交崩溃报告;在您的情况下,您正试图保持应用程序运行并显示一条消息,这具有相同的效果:保持应用程序运行意味着执行应用程序自己的代码,然后应用程序可以自由尝试写入可能损坏的用户数据.

考虑一个基于 Core Data 的应用程序,其中模型对象被更新,然后被保存:

person.name = name;
person.age = age; // an exception occurs here
person.birthday = birthday;
[context save: NULL];

在崩溃时,托管对象上下文包含部分更新的记录——当然不是您想要保存到数据库中的内容。但是,如果您的未捕获异常处理程序继续保持您的应用程序执行,那么您的应用程序中的任何网络连接、计时器或其他挂起的 runloop 调度也将运行。如果从 runloop 分派的任何应用程序代码包含对 -[NSManagedObjectContext save:] 的调用,您会将部分更新的记录写入数据库,从而破坏用户数据。

当您的应用程序处于未知/不确定状态时,最安全的做法是简单地退出。

于 2013-05-03T16:29:52.770 回答
1

好吧,不知道这是否会对您有所帮助,但在我的应用程序中,我设法向UIAlertView用户展示了有关崩溃、异常类型、其描述和堆栈跟踪(全部使用该NSSetUncaughtExceptionHandler方法)的解释,如下所示:

西班牙语样本

然后,尽管应用程序可能不稳定,我还是提供了终止应用程序或继续的推荐选项。就我而言,它部分影响了应用程序的功能,因此在大多数情况下,用户可以保存其工作并安全地关闭应用程序。

如果您愿意,我可以编辑答案并在此处发布代码(我必须搜索我的 Xcode 项目文件夹,这就是我没有发布它的原因)。

编辑:

在 AppDelegate 委托的方法上willFinishLaunchingWithOptions,我设置了NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

然后我创建处理程序方法如下:

static void uncaughtExceptionHandler(NSException *exception)
{
    [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"kDisculpe", nil) message:[NSString stringWithFormat:@"%@ %@%@ %@%@ %@", NSLocalizedString(@"kErrorText", nil), [exception name], NSLocalizedString(@"kErrorDescripcion", nil), [exception reason], NSLocalizedString(@"kErrorTrazaPila", nil), [exception callStackReturnAddresses]] delegate:[[UIApplication sharedApplication] delegate] cancelButtonTitle:NSLocalizedString(@"kContinuar", nil) otherButtonTitles:NSLocalizedString(@"kSalir", nil), nil] show];
    [[NSRunLoop currentRunLoop] run];
}

然后在我设置的 AlertView 的委托方法上clickedButtonAtIndex

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if ([[alertView title] isEqualToString:NSLocalizedString(@"kDisculpe", nil)]) {
        switch (buttonIndex) {
            case 0:
                if ([[alertView title] isEqualToString:NSLocalizedString(@"kDisculpe", nil)]) {
                    [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"kAdvertencia", nil) message:NSLocalizedString(@"kAppContinuaraInestable", nil) delegate:[[UIApplication sharedApplication] delegate] cancelButtonTitle:NSLocalizedString(@"kContinuar", nil) otherButtonTitles:nil] show];
                }
                break;
            case 1:
                exit(0);
                break;
        }
    }
}

请注意,我所做的唯一重要的事情是[[NSRunLoop currentRunLoop] run];我希望这会对您有所帮助。

于 2013-05-03T14:40:52.320 回答