簡體   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