2016-08-21 3 views
1

Я пытаюсь показать оповещение пользователя после приложения crash, чтобы дать некоторую информацию о сбое. Такие как; «У вас крушение, мы исправим как можно скорее». Можно ли показать здесь предупреждение?Показать предупреждение после приложения crash iOS

Я получил эту часть кода отсюда, и я поставил в нее предупреждение.

- (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.Я использовал его для сбора сведений об исключениях и отправки их назад к моему веб-сервер, а затем анализировать их, чтобы исправить проблемы.

в моей 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

Смежные вопросы