1. 程式人生 > >iOS閃退問題,避免閃退看我就足夠了, try catch等方法

iOS閃退問題,避免閃退看我就足夠了, try catch等方法

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

這樣就可以啦