我想在应用关闭之前显示玻璃碎片动画。通过设置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);
}
但是我甚至无法在视图中添加一个简单的图像,应用程序在下一个绘图周期之前崩溃。在app关闭之前,是否可以在屏幕上显示任何内容?
答案 0 :(得分:3)
一旦发出异常,应用程序的状态就不确定了;没有人知道你的应用程序在做什么,虽然有很多事情可能会出错(参见上面的链接),我将在这里关注的是数据损坏。
一些崩溃记者试图在程序终止后立即通过网络提交崩溃报告;在您的情况下,您正在尝试保持应用程序运行并显示消息,这具有相同的效果:保持应用程序运行意味着执行应用程序自己的代码,然后应用程序可以自由尝试编写可能已损坏的用户数据
考虑基于核心数据的应用程序,其中更新模型对象,然后保存:
person.name = name;
person.age = age; // an exception occurs here
person.birthday = birthday;
[context save: NULL];
在崩溃时,托管对象上下文包含部分更新的记录 - 当然不是您想要保存到数据库的内容。但是,如果未捕获的异常处理程序继续执行以保持应用程序正常运行,则还将运行应用程序中的任何网络连接,计时器或其他挂起的runloop调度。如果从runloop调度的任何应用程序代码包含对 - [NSManagedObjectContext save:]的调用,则会将部分更新的记录写入数据库,从而破坏用户的数据。
当您的应用程序处于未知/非确定状态时,最安全的做法就是退出。
答案 1 :(得分: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];
我希望这会对你有帮助。