iOS閃退問題,避免閃退看我就足夠了, try catch等方法
阿新 • • 發佈:2019-01-01
Java是有try catch 的,提前驗證正確性。iOS也有嘛,但是隻能捕獲一些陣列越界,資料型別不對之類的異常,Xcode不識別,那麼就崩潰,閃退了。
提高使用者體驗,不閃退,從我開始,哈哈,特簡單的嘛
@try {
//執行的程式碼,如果異常,就會丟擲,程式不繼續執行啦
} @catch (NSException *exception) {
//捕獲異常
} @finally {
//這裡一定執行,無論你異常與否
}
邏輯怎麼寫,就看你了,看專案了
但是比如野指標或者記憶體溢位,就不行了。so這裡可以捕獲這些異常的
上程式碼
定義一個物件
.h裡面
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface UncaughtExceptionHandler : NSObject
{
BOOL dismissed;
}
@end
void HandleException(NSException *exception);
void SignalHandler(int signal);
void InstallUncaughtExceptionHandler(void);
.m 裡面
#import "UncaughtExceptionHandler.h"
#import <UIKit/UIKit.h>
#include <libkern/OSAtomic.h>
#include <execinfo.h>
#import "AppDelegate.h"
NSString *const UncaughtExceptionHandlerSignalExceptionName [email protected]"UncaughtExceptionHandlerSignalExceptionName";
NSString *const UncaughtExceptionHandlerSignalKey [email protected]"UncaughtExceptionHandlerSignalKey";
NSString *const UncaughtExceptionHandlerAddressesKey [email protected]"UncaughtExceptionHandlerAddressesKey";
volatile int32_t UncaughtExceptionCount =0;
const int32_t UncaughtExceptionMaximum =10;
const NSInteger UncaughtExceptionHandlerSkipAddressCount =4;
const NSInteger UncaughtExceptionHandlerReportAddressCount =5;
@implementation UncaughtExceptionHandler
+ (NSArray *)backtrace {// 程式崩潰2(程式崩潰第二步走的方法)
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)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex {
if (anIndex ==0){
dismissed =YES;
}else if(anIndex==1) {
NSLog(@"ssssssss");
}
}
- (void)validateAndSaveCriticalApplicationData {
// 崩潰攔截可以做的事,寫在這個方法也是極好的
NSLog(@"崩潰了");
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"溫馨提示" message:@"開啟" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction * cancelAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
[alert addAction:cancelAction];
UIViewController * rootViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
[rootViewController presentViewController:alert animated:YES completion:^{
}];
}
// 程式崩潰3(程式崩潰是第三進入的方法)
- (void)handleException:(NSException *)exception {
[self validateAndSaveCriticalApplicationData];
NSString *message = [NSString stringWithFormat:NSLocalizedString(@"如果點選繼續,程式有可能會出現其他的問題,建議您還是點選退出按鈕並重新開啟\n\n"@"異常原因如下:\n%@\n%@",nil),[exception reason],[[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]];
UIAlertView *alert =[[UIAlertView alloc]initWithTitle:NSLocalizedString(@"抱歉,程式出現了異常",nil)
message:message
delegate:self
cancelButtonTitle:NSLocalizedString(@"退出",nil)
otherButtonTitles:NSLocalizedString(@"繼續",nil), nil];
NSLog(@"異常顯示了");
[alert show];
UIAlertAction *act1 = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertController *vc = [UIAlertController alertControllerWithTitle:@"異常啦" message:nil preferredStyle:UIAlertControllerStyleAlert];
[vc addAction:act1];
UIViewController *rootViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
[rootViewController presentViewController:vc animated:YES completion:nil];
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
while (!dismissed) {
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 = [UncaughtExceptionHandler backtrace];
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(void) {
NSSetUncaughtExceptionHandler(&HandleException);
signal(SIGHUP, SignalHandler);//本訊號在使用者終端連線(正常或非正常)結束時發出, 通常是在終端的控制程序結束時, 通知同一session內的各個作業
signal(SIGINT, SignalHandler);//程式終止(interrupt)訊號, 在使用者鍵入INTR字元(通常是Ctrl-C)時發出,用於通知前臺程序組終止程序。
signal(SIGQUIT, SignalHandler);//類似於一個程式錯誤訊號。
signal(SIGABRT,SignalHandler);//呼叫abort函式生成的訊號。
signal(SIGILL,SignalHandler);//用來立即結束程式的執行. 本
signal(SIGSEGV,SignalHandler);//試圖訪問未分配給自己的記憶體, 或試圖往沒有寫許可權的記憶體地址寫資料.
signal(SIGFPE,SignalHandler);//在發生致命的算術運算錯誤時發出.
signal(SIGBUS,SignalHandler);//訪問不屬於自己儲存空間或只讀儲存空間
signal(SIGPIPE,SignalHandler);//管道破裂。
}
之後AppDelegate.h裡面
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
return YES;
}
這樣就可以啦