2016-08-21 75 views
1

我想在崩溃应用程序后显示用户alertview,以提供有关崩溃的一些信息。如; “你崩溃了,我们会尽快解决。”可以在这里显示alertview吗?在应用程序崩溃后显示alertview iOS

我从这里得到了这部分代码,我把alertview放在里面。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 

     NSSetUncaughtExceptionHandler(&myExceptionHandler); 

} 

void myExceptionHandler(NSException *exception) 
{ 

    UIAlertView *alert = [[UIAlertView alloc] 
         initWithTitle:@"" 
         message:@"You got crash, we will fix as soon as possible!" 
         delegate:nil 
         cancelButtonTitle:@"Okay" 
         otherButtonTitles:nil, nil]; 
    [alert show]; 

    NSArray *stack = [exception callStackReturnAddresses]; 
    NSLog(@"Stack trace: %@", stack); 

} 

我也试过这段代码来显示警报。

[alert performSelectorOnMainThread:@selector(show) withObject:nil waitUntilDone:YES]; 
+4

大多数时候,你将不能中断崩溃,并继续执行代码,因为你的程序可以在一个非常不一致的状态。您最好的选择是使用崩溃报告工具,并在用户重新启动应用程序时显示警报视图。 – deadbeef

+2

不要这样做。它有什么有用的目的?碰撞中断了我正在做的事情。这很烦人。这次事故发生后的警报只是中断的两倍。还有三倍的烦恼,因为你打断了我正在故意做的事情。 – gnasher729

+3

这不能成立。当应用程序崩溃时,它崩溃。之后没有任何代码正在执行。 –

回答

5

你应该做到这一点。

这是为什么:

  1. 当你的应用程序崩溃,应用程序处于非常不稳定的状态。您可能试图访问应用程序之外的内存,假设某些对象属于特定类型,并且不是,等等。如果您继续执行代码,则可能会覆盖/删除/损坏您的应用用户数据,因为您无法确定代码是否确实按照您的要求执行了操作。
  2. 由于这种不稳定状态,您不应该在崩溃时调用任何(!!)非异步安全代码,其中包括任何Objective-C代码。只有C的一个子集是允许的,你不应该在那个时候分配任何内存。
  3. 您的代码只会触发警报(如果它在大多数情况下仍然可以使用,则由于上述情况)会发生未处理的异常。但这些只是你的应用程序可能崩溃的原因的一个子集。

你可以做什么,而是要求用户在下次启动应用程序时发生崩溃之前做了什么。为了检测您的应用程序是否崩溃,您可以使用多个第三方服务或(开源)库来检测崩溃并在碰撞时安全地收集堆栈跟踪。

0

我需要在碰撞发生时显示警告提醒。我这样做,它的工作。

请注意,只有在真正有必要的情况下,您才应该使用这样的代码(因为这是我的情况,因为@Kerni here并不是一个好习惯,我用它来收集异常细节并发送它们回到我的Web服务器,然后分析他们解决问题。

在我AppDelegate.m

#import "UncaughtExceptionHandler.h" 
//[...] 

- (void)installUncaughtExceptionHandler 
{ 
    InstallUncaughtExceptionHandler(); 
} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    //[...] 

    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); 

    //[...] 

} 

我UncaughtExceptionHandler.h

// 
// UncaughtExceptionHandler.h 
// UncaughtExceptions 
// 
// Created by Matt Gallagher on 2010/05/25. 
// Copyright 2010 Matt Gallagher. All rights reserved. 
// 
// Permission is given to use this source code file, free of charge, in any 
// project, commercial or otherwise, entirely at your risk, with the condition 
// that any redistribution (in part or whole) of source code must retain 
// this copyright and permission notice. Attribution in compiled projects is 
// appreciated but not required. 
// 

#import <UIKit/UIKit.h> 

@interface UncaughtExceptionHandler : NSObject<UIAlertViewDelegate> 
{ 
    NSException* currentException; 
} 

@end 

void InstallUncaughtExceptionHandler(); 

我UncaughtExceptionHandler.m

// 
// UncaughtExceptionHandler.m 
// UncaughtExceptions 
// 
// Created by Matt Gallagher on 2010/05/25. 
// Copyright 2010 Matt Gallagher. All rights reserved. 
// 
// Permission is given to use this source code file, free of charge, in any 
// project, commercial or otherwise, entirely at your risk, with the condition 
// that any redistribution (in part or whole) of source code must retain 
// this copyright and permission notice. Attribution in compiled projects is 
// appreciated but not required. 
// 

#import "UncaughtExceptionHandler.h" 
#include <libkern/OSAtomic.h> 
#include <execinfo.h> 

NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName"; 
NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey"; 
NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey"; 

volatile int32_t UncaughtExceptionCount = 0; 
const int32_t UncaughtExceptionMaximum = 10; 

const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4; 
const NSInteger UncaughtExceptionHandlerReportAddressCount = 5; 

@implementation UncaughtExceptionHandler 

+ (NSArray *)backtrace 
{ 
    void* callstack[128]; 
    int frames = backtrace(callstack, 128); 
    char **strs = backtrace_symbols(callstack, frames); 

    int i; 
    NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames]; 
    for (
     i = UncaughtExceptionHandlerSkipAddressCount; 
     i < UncaughtExceptionHandlerSkipAddressCount + 
     UncaughtExceptionHandlerReportAddressCount; 
     i++) 
    { 
     [backtrace addObject:[NSString stringWithUTF8String:strs[i]]]; 
    } 
    free(strs); 

    return backtrace; 
} 

- (void)handleException:(NSException *)exception 
{ 
    //here you can show your alert 
    UIAlertView *alert = [[UIAlertView alloc] 
         initWithTitle:@"" 
         message:@"You got crash, we will fix as soon as possible!" 
         delegate:nil 
         cancelButtonTitle:@"Okay" 
         otherButtonTitles:nil, nil]; 
    [alert show]; 

    NSString* reason = [exception reason]; 
    if([reason length]>200) 
    { 
     reason = [[reason substringToIndex:200] stringByAppendingString:@" [...]"]; 
    } 

    CFRunLoopRef runLoop = CFRunLoopGetCurrent(); 
    CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop); 

    for (NSString *mode in (__bridge NSArray *)allModes) 
    { 
     CFRunLoopRunInMode((CFStringRef)mode, 0.001, false); 
    } 

    CFRelease(allModes); 

    NSSetUncaughtExceptionHandler(NULL); 
    signal(SIGABRT, SIG_DFL); 
    signal(SIGILL, SIG_DFL); 
    signal(SIGSEGV, SIG_DFL); 
    signal(SIGFPE, SIG_DFL); 
    signal(SIGBUS, SIG_DFL); 
    signal(SIGPIPE, SIG_DFL); 

    if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName]) 
    { 
     kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]); 
    } 
    else 
    { 
     [exception raise]; 
    } 
} 

@end 

void HandleException(NSException *exception) 
{ 
    int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); 
    if (exceptionCount > UncaughtExceptionMaximum) 
    { 
     return; 
    } 

    NSArray *callStack = [exception callStackSymbols]; 
    NSMutableDictionary *userInfo = 
    [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]]; 
    [userInfo 
    setObject:callStack 
    forKey:UncaughtExceptionHandlerAddressesKey]; 

    [[[UncaughtExceptionHandler alloc] init] 
    performSelectorOnMainThread:@selector(handleException:) 
    withObject: 
    [NSException 
     exceptionWithName:[exception name] 
     reason:[exception reason] 
     userInfo:userInfo] 
    waitUntilDone:YES]; 
} 

void SignalHandler(int signal) 
{ 
    int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); 
    if (exceptionCount > UncaughtExceptionMaximum) 
    { 
     return; 
    } 

    NSMutableDictionary *userInfo = 
    [NSMutableDictionary 
    dictionaryWithObject:[NSNumber numberWithInt:signal] 
    forKey:UncaughtExceptionHandlerSignalKey]; 

    NSArray *callStack = [UncaughtExceptionHandler backtrace]; 
    [userInfo 
    setObject:callStack 
    forKey:UncaughtExceptionHandlerAddressesKey]; 

    [[[UncaughtExceptionHandler alloc] init] 
    performSelectorOnMainThread:@selector(handleException:) 
    withObject: 
    [NSException 
     exceptionWithName:UncaughtExceptionHandlerSignalExceptionName 
     reason: 
     [NSString stringWithFormat: 
     NSLocalizedString(@"Signal %d was raised.", nil), 
     signal] 
     userInfo: 
     [NSDictionary 
     dictionaryWithObject:[NSNumber numberWithInt:signal] 
     forKey:UncaughtExceptionHandlerSignalKey]] 
    waitUntilDone:YES]; 
} 

void InstallUncaughtExceptionHandler() 
{ 
    NSSetUncaughtExceptionHandler(&HandleException); 
    signal(SIGABRT, SignalHandler); 
    signal(SIGILL, SignalHandler); 
    signal(SIGSEGV, SignalHandler); 
    signal(SIGFPE, SignalHandler); 
    signal(SIGBUS, SignalHandler); 
    signal(SIGPIPE, SignalHandler); 
} 
+0

使用PLCrashReporter并在下一次应用程序启动时发送数据。这是保存,提供更好的数据,更准确的堆栈跟踪等。你的代码是一个超过6年的例子。不要使用它。 – Kerni