崩溃应用iOS后显示alertview

时间:2016-08-21 12:45:59

标签: ios objective-c exception uialertview

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

我从这里得到了这部分代码,并在其中加入了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];

2 个答案:

答案 0 :(得分:5)

你应该那样做。

原因如下:

  1. 当您的应用崩溃时,应用处于非常不稳定的状态。您本可以尝试访问应用程序范围之外的内存,假设某个对象属于特定类型,而不是等等。如果您继续执行代码,则可能会覆盖/删除/损坏您的应用用户数据,因为您无法确定您的代码实际上是否符合您的要求。
  2. 由于该不稳定状态,您不应在崩溃时调用任何(!!)非异步安全代码,其中包括任何Objective-C代码。只允许C的一个子集,此时不应分配任何内存。
  3. 对于未处理的异常,您的代码只会触发警报(如果它在大多数情况下甚至可能由于上述情况而起作用)。但这些只是您的应用可能崩溃的原因的一部分。
  4. 您可以做的是询问用户在您的应用程序下次启动时发生崩溃之前他做了什么。要检测您的应用程序是否崩溃,您可以使用多个第三方服务或(开源)库来检测崩溃并在崩溃时(安全地)收集堆栈跟踪。

答案 1 :(得分:0)

发生崩溃时我需要显示警告提醒。我做到了这一点并且有效。

请注意,只有在真的有必要时才应该使用这样的代码(就像我的情况一样,因为这不是@Kerni here所说的好习惯。我用它来收集异常细节并将它们发送回我的网络服务器,然后分析它们以解决问题。

在我的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);
}