繁体   English   中英

在iOS应用崩溃后显示AlertView

[英]Show alertview after crash app iOS

我试图在崩溃应用程序后向用户显示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];

你不应该那样做。

原因如下:

  1. 当您的应用崩溃时,该应用处于非常不稳定的状态。 您可能曾尝试访问应用程序无法访问的内存,并假设某些对象属于特定类型,而实际上并非如此。 如果您继续执行代码,则可能会覆盖/删除/损坏应用程序用户数据,因为您无法确定代码是否确实执行了您希望执行的操作。
  2. 由于状态不稳定,因此您不应在崩溃时调用任何(!!)非异步安全代码,包括任何Objective-C代码。 只允许C的一个子集,此时您不应分配任何内存。
  3. 您的代码只会针对未处理的异常触发警报(如果由于上述原因在大多数情况下甚至仍然有效)。 但这只是您的应用可能崩溃的部分原因。

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

发生崩溃时,我需要显示警告警报。 我做到了,而且有效。

请注意,只有在真正必要时,才应使用这样的代码(就我而言,这不是@Kerni 在此处所说的好习惯。我用它来收集异常详细信息并将其发送回我的网站服务器,然后对其进行分析以解决问题。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM