Container類型的crash和NSString類型的crash

首先參考一下自己之前寫的《method swizzing》這篇,特別是對類簇的methodSwizzing。

Container 類型的crash 指的是容器類的crash,常見的有NSArray/NSMutableArray/NSDictionary/NSMutableDictionary/NSCache的crash。 一些常見的越界、插入nil等錯誤操作均會導(dǎo)致此類crash發(fā)生。 由于產(chǎn)生的原因比較簡單,就不展開來描述了。

該類crash雖然比較容易排查,但是其在app crash概率總比還是挺高,所以有必要對其進(jìn)行防護(hù)。另外NSString也有類似的crash防護(hù)措施,在此篇中一并舉例說明。

一、Container類型和NSString類型常見crash

(1) [aMutableDictionary setObject:nil forKey:]; object can not be nil.

(2) [aString hasSuffix:nil]; nil argument crash.

[aString hasPrefix:nil]; nil argument crash.

(3) aString = [NSMutableString stringWithString:nil];nil argument crash.

(4) aString = [[NSString alloc] initWithString:nil]; nil argument crash.

(5) aURL = [NSURL fileURLWithPath:nil]; nil argument crash.

(6) NSArray 數(shù)組越界 crash。

二、使用method swizzing對常見crash防護(hù)舉例

這里對NSString、NSMutableDictionary和NSArray常見的幾個crash舉例如下:

(1)對NSString的hasSuffix:和hasPrefix:進(jìn)行預(yù)防:

#import "NSString+CrashGurad.h"
#import <objc/runtime.h>

@implementation NSString (CrashGurad)

#pragma mark Class Method

+(void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [[self class] swizzedMethod:@selector(hasSuffix:) withMethod:@selector(crashGuard_hasSuffix:)];
        [[self class] swizzedMethod:@selector(hasPrefix:) withMethod:@selector(crashGuard_hasPrefix:)];
    });
}

+(void)swizzedMethod:(SEL)originalSelector withMethod:(SEL )swizzledSelector {
    
    Method fromMethod = class_getInstanceMethod(objc_getClass("__NSCFConstantString"), originalSelector);
    Method toMethod = class_getInstanceMethod(objc_getClass("__NSCFConstantString"), swizzledSelector);
    method_exchangeImplementations(fromMethod, toMethod);
}

#pragma mark Swizzled Method

-(BOOL)crashGuard_hasSuffix:(NSString *)str {
    if(!str){
        // 打印崩潰信息,棧信息 等
        NSLog(@"selector \"hasSuffix\" crash for the the suffix is nil!");
        return NO;
    } else {
        return [self crashGuard_hasSuffix:str];
    }
}

- (BOOL)crashGuard_hasPrefix:(NSString *)str {
    if(!str){
        // 打印崩潰信息,棧信息 等
        NSLog(@"selector \"hasPrefix\" crash for the the prefix is nil!");
        return NO;
    } else {
        return [self crashGuard_hasPrefix:str];
    }
}

(2)對NSArray的objectAtIndex:的crash預(yù)防如下:

#import "NSArray+CrashGuard.h"
#import <objc/runtime.h>

@implementation NSArray (CrashGuard)
+(void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method fromMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:));
        Method toMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(crashGuard_objectAtIndex:));
        method_exchangeImplementations(fromMethod, toMethod);
    });
}

#pragma mark Swizzled Method

-(id)crashGuard_objectAtIndex:(NSUInteger)index {
    if(self.count-1 < index) {
        // 打印崩潰信息,棧信息 等
        NSLog(@"selector \"objectAtIndex\" crash for the index beyond  the boundary!");
        return nil;
    } else {
        return [self crashGuard_objectAtIndex:index];
    }
}

@end

3)對NSMutableDictionary的setObject:forKey:的crash預(yù)防如下:

#import "NSMutableDictionary+CrashGuard.h"
#import <objc/runtime.h>

@implementation NSMutableDictionary (CrashGuard)
+(void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method fromMethod = class_getInstanceMethod(objc_getClass("__NSDictionaryM"), @selector(setObject:forKey:));
        Method toMethod = class_getInstanceMethod(objc_getClass("__NSDictionaryM"), @selector(crashGuard_setObject:forKey:));
        method_exchangeImplementations(fromMethod, toMethod);
    });
}

#pragma mark Swizzled Method

-(void)crashGuard_setObject:(id)object forKey:(NSString *)key {
    if(!object) {
        // 打印崩潰信息,棧信息 等
        NSLog(@"selector \"setObject:forKey:\" crash for the the object is nil!");
        
    } else {
        [self crashGuard_setObject:object forKey:key];
    }
    
}
@end

總結(jié):

Container crash 類型和NSString類型的crash防護(hù)方案比較簡單,針對于NSArray/NSMutableArray/NSDictionary/NSMutableDictionary的一些常用的會導(dǎo)致崩潰的API進(jìn)行method swizzling,然后在swizzle的新方法中加入一些條件限制和判斷,從而讓這些API變的安全。當(dāng)然,在程序進(jìn)入這些swizzle的方法后,我們需要及時記錄并上傳相關(guān)的日志信息到后臺服務(wù)器,并及時review相關(guān)的內(nèi)容,將迭代中將有隱患的代碼改掉。

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

相關(guān)閱讀更多精彩內(nèi)容

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