IOS系統(tǒng)閃退異常(Crash)捕獲處理

我們的程序經(jīng)常出現(xiàn)異常造成閃退的現(xiàn)象,對(duì)于已經(jīng)發(fā)布的APP,如何捕捉到這些異常,及時(shí)進(jìn)行更新解決閃退,提高體驗(yàn)感呢?
對(duì)于一些簡(jiǎn)單,比如一些后臺(tái)數(shù)據(jù)的處理,容易重現(xiàn)數(shù)組越界,字典空指針錯(cuò)誤的,我們用oc的runtime方法進(jìn)行捕獲。比如NSArray的數(shù)組越界問(wèn)題。
源碼地址:GitHub地址

//
//  ViewController.m
//  CatchCrash
//
//  Created by Sem on 2020/8/28.
//  Copyright ? 2020 SEM. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   
    // Do any additional setup after loading the view.
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSArray *dd =@[@"1",@"2"];
       NSString *z =dd[3];
       NSLog(@"~~~~~%@",z);
}
@end

我們可以通過(guò)runtime進(jìn)行方法替換,比如我們捕獲NSArray的數(shù)組越界問(wèn)題,注意NSArray 是個(gè)類(lèi)簇所以不能簡(jiǎn)單添加類(lèi)目

+(BOOL)SQ_HookOriInstanceMethod:(SEL)oriSel NewInstanceMethod:(SEL)newSel{
    Class class = objc_getRequiredClass("__NSArrayI");
    Method origMethod = class_getInstanceMethod(class, oriSel);
    Method newMethod = class_getInstanceMethod(self, newSel);
    if(!origMethod||!newMethod){
        return NO;
    }
    method_exchangeImplementations(origMethod, newMethod);
    return YES;
    
}
-(id)objectAtIndexedSubscriptNew:(NSUInteger)index{
    if(index>=self.count){
        //代碼處理 上傳服務(wù)器.
        return nil;
    }
    return [self objectAtIndexedSubscriptNew:index] ;
}

當(dāng)然這種捕獲只能捕獲單一的問(wèn)題,還有其他的報(bào)錯(cuò),那就要寫(xiě)很多的分類(lèi)處理,如何進(jìn)行統(tǒng)一的捕捉呢,我們查看下報(bào)錯(cuò)信息看下能不找到有用的信息。


image.png

如圖我們看了報(bào)錯(cuò)的方法棧??吹接衛(wèi)ibobjc的調(diào)用。這個(gè)就很熟悉了,去看下runtime的源碼。可以找到set_terminate設(shè)置中止的回調(diào),也就是如果出現(xiàn)報(bào)錯(cuò),系統(tǒng)會(huì)回調(diào)這個(gè)函數(shù),如果外界沒(méi)有傳這個(gè)函數(shù)objc_setUncaightExceptionHandler,系統(tǒng)會(huì)使用默認(rèn)的實(shí)現(xiàn)。 我們只要調(diào)用NSSetUncaughtExceptionHandler就可以設(shè)置這個(gè)方法句柄,系統(tǒng)出現(xiàn)報(bào)錯(cuò)時(shí)候,回調(diào)這個(gè)方法,從而讓我們對(duì)這個(gè)錯(cuò)誤進(jìn)行處理.
在AppDelegate里面設(shè)置這個(gè)方法句柄

NSSetUncaughtExceptionHandler(&HandleException);

然后就可以捕捉異常 ,上傳服務(wù)或者保存在本地。

void HandleException(NSException *exception)
{
    int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
    if (exceptionCount > UncaughtExceptionMaximum)
    {
        return;
    }
    //獲取方法調(diào)用棧
    NSArray *callStack = [UncaughtExceptionHandler backtrace];
    NSMutableDictionary *userInfo =
        [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
    [userInfo
        setObject:callStack
        forKey:UncaughtExceptionHandlerAddressesKey];
    
    [[[[UncaughtExceptionHandler alloc] init] autorelease]
        performSelectorOnMainThread:@selector(handleException:)
        withObject:
            [NSException
                exceptionWithName:[exception name]
                reason:[exception reason]
                userInfo:userInfo]
        waitUntilDone:YES];
}

然后在這個(gè)對(duì)象中通過(guò)runloop,保住線程,處理后再崩潰.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容