Kirdok
Kirdok

Reputation: 1914

Show alertview after crash app iOS

I am trying to show the user alertview after crash app for give some information about crash. Such as; "You got crash, we will fix as soon as possible." Is it possible to show the alertview in here?

I got this part of code from here and i put alertview inside it.

- (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);

}

I also tried this code for show the alert.

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

Upvotes: 1

Views: 1098

Answers (2)

ddb
ddb

Reputation: 2435

I needed to show a warning alert when a crash happened. I did this and it works.

Please, note that you should use such a code only if really necessary (as it was in my case, as it is not a good practice as said by @Kerni here. I used it to collect exception details and send them back to my web server and then analyze them to fix issues.

In my AppDelegate.m

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

- (void)installUncaughtExceptionHandler
{
    InstallUncaughtExceptionHandler();
}

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

    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

    //[...]

}

My 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();

my 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);
}

Upvotes: 0

Kerni
Kerni

Reputation: 15339

You should not do that.

Here is why:

  1. When your app crashed, the app is in an very unstable state. You could have tried to access memory that is outside of your apps reach, assume some object is of a specific type and it is not, and more. If you continue to execute code, you might overwrite/delete/damage your apps user data as you can't be sure your code actually does what you want it to do.
  2. Because of that unstable state, you should not call any (!!) non async-safe code at crash time, which includes any Objective-C code. Only a subset of C is allowed and you should not allocate any memory at that time.
  3. Your code would only trigger an alert (if it would even work in most cases due to the above) for unhandled exceptions. But those are only a subset of reason that your app might crash.

What you can do instead is asking the user what he did before the crash occurred when your app starts the next time. To detect if your app crashed, you can use multiple 3rd party services or (open source) libraries to detect a crash and (safely) collect stacktraces at crash time.

Upvotes: 5

Related Questions