2016-08-21 70 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

相關問題