iOS崩溃处理机制:Container类型crash防护

Container类型的crash 指的是容器类的crash,常见的有NSArray/NSMutableArray/NSDictionary/NSMutableDictionary/NSCache的crash。 一些常见的越界,插入nil,等错误操作均会导致此类crash发生。

解决方案:
对于容易造成crash的方法,自定义方法进行交换,并在自定义的方法中加入一些条件限制和判断。

具体方式:
1、NSArray crash:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSArray (XZCrash)

+ (void)xz_enableArrayProtector;

@end

NS_ASSUME_NONNULL_END
/**
 
 iOS 8:下都是__NSArrayI
 iOS11: 之后分 __NSArrayI、  __NSArray0、__NSSingleObjectArrayI
 
 iOS11之前:arr@[]  调用的是[__NSArrayI objectAtIndexed]
 iOS11之后:arr@[]  调用的是[__NSArrayI objectAtIndexedSubscript]
 
 arr为空数组
 *** -[__NSArray0 objectAtIndex:]: index 12 beyond bounds for empty NSArray
 
 arr只有一个元素
 *** -[__NSSingleObjectArrayI objectAtIndex:]: index 12 beyond bounds [0 .. 0]
 
 */

#import "NSArray+XZCrash.h"
#import "NSObject+XZSwizzle.h"
#import 

@implementation NSArray (XZCrash)

+ (void)xz_enableArrayProtector {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        /**
         __NSArray0 仅仅初始化后不含有元素的数组          ( NSArray *arr2 =  [[NSArray alloc]init]; )
         __NSSingleObjectArrayI 只有一个元素的数组      ( NSArray *arr3 =  [[NSArray alloc]initWithObjects: @"1",nil]; )
         __NSPlaceholderArray 占位数组                ( NSArray *arr4 =  [NSArray alloc]; )
         __NSArrayI 初始化后的不可变数组                ( NSArray *arr1 =  @[@"1",@"2"]; )
         */
        Class __NSArray = objc_getClass("NSArray");
        Class __NSArrayI = objc_getClass("__NSArrayI");
        Class __NSSingleObjectArrayI = objc_getClass("__NSSingleObjectArrayI");
        Class __NSArray0 = objc_getClass("__NSArray0");
        
        
        [self xz_classSwizzleMethodWithClass:__NSArray orginalMethod:@selector(arrayWithObjects:count:) replaceMethod:@selector(xz_arrayWithObjects:count:)];
        
        
        // [arr objectAtIndex:];
        [self xz_instanceSwizzleMethodWithClass:__NSArrayI orginalMethod:@selector(objectAtIndex:) replaceMethod:@selector(xz_objectAtIndex:)];
        
        // arr[];
        [self xz_instanceSwizzleMethodWithClass:__NSArrayI orginalMethod:@selector(objectAtIndexedSubscript:) replaceMethod:@selector(xz_objectAtIndexedSubscript:)];
        
        // 数组为空
        [self xz_instanceSwizzleMethodWithClass:__NSArray0 orginalMethod:@selector(objectAtIndex:) replaceMethod:@selector(xz_objectAtIndexedNullarray:)];
        
        // 数组count == 1
        [self xz_instanceSwizzleMethodWithClass:__NSSingleObjectArrayI orginalMethod:@selector(objectAtIndex:) replaceMethod:@selector(xz_objectAtIndexedArrayCountOnlyOne:)];
        
        // objectsAtIndexes:
        [self xz_instanceSwizzleMethodWithClass:__NSArray orginalMethod:@selector(objectsAtIndexes:) replaceMethod:@selector(xz_objectsAtIndexes:)];
        
        // 以下方法调用频繁,替换可能会影响性能
        // getObjects:range:
        [self xz_instanceSwizzleMethodWithClass:__NSArray orginalMethod:@selector(getObjects:range:) replaceMethod:@selector(xz_getObjectsNSArray:range:)];
        [self xz_instanceSwizzleMethodWithClass:__NSSingleObjectArrayI orginalMethod:@selector(getObjects:range:) replaceMethod:@selector(xz_getObjectsNSSingleObjectArrayI:range:)];
        [self xz_instanceSwizzleMethodWithClass:__NSArrayI orginalMethod:@selector(getObjects:range:) replaceMethod:@selector(xz_getObjectsNSArrayI:range:)];
    });
}


// 创建类
+ (instancetype)xz_arrayWithObjects:(const id  _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt {
    id instance = nil;
    
    @try {
        instance = [self xz_arrayWithObjects:objects count:cnt];
        
    } @catch (NSException *exception) {
        
        // 去掉nil的数据,用新数据重新初始化数组
        NSInteger newObjectsIndex = 0;
        id _Nonnull __unsafe_unretained newObjects[cnt];
        
        for (int i = 0; i < cnt; i ++) {
            if (objects[i] != nil) {
                newObjects[newObjectsIndex] = objects[i];
                newObjectsIndex ++;
            }
        }
        instance = [self xz_arrayWithObjects:newObjects count:newObjectsIndex];
        
    } @finally {
        return instance;
    }
}


- (id)xz_objectAtIndex:(NSUInteger)index {
    
    id object = nil;
    
    @try {
        object = [self xz_objectAtIndex:index];
        
    } @catch (NSException *exception) {
        
    } @finally {
        return object;
    }
}

- (id)xz_objectAtIndexedSubscript:(NSUInteger)index {
    
    id object = nil;
    
    @try {
        object = [self xz_objectAtIndexedSubscript:index];
        
    } @catch (NSException *exception) {
        
    } @finally {
        return object;
    }
}

- (id)xz_objectAtIndexedNullarray:(NSUInteger)index {
    
    id object = nil;
    
    @try {
        object = [self xz_objectAtIndexedNullarray:index];
        
    } @catch (NSException *exception) {
        
    } @finally {
        return object;
    }
}

- (id)xz_objectAtIndexedArrayCountOnlyOne:(NSUInteger)index {
    
    id object = nil;
    
    @try {
        object = [self xz_objectAtIndexedArrayCountOnlyOne:index];
        
    } @catch (NSException *exception) {
        
    } @finally {
        return object;
    }
}

- (NSArray *)xz_objectsAtIndexes:(NSIndexSet *)indexes {
    
    NSArray *returnArray = nil;
    
    @try {
        returnArray = [self xz_objectsAtIndexes:indexes];
        
    } @catch (NSException *exception) {
        
    } @finally {
        return returnArray;
    }
}


#pragma mark getObjects:range:
- (void)xz_getObjectsNSArray:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    @try {
        [self xz_getObjectsNSArray:objects range:range];
    } @catch (NSException *exception) {
    } @finally {
    }
}

- (void)xz_getObjectsNSSingleObjectArrayI:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    @try {
        [self xz_getObjectsNSSingleObjectArrayI:objects range:range];
    } @catch (NSException *exception) {
    } @finally {
    }
}

- (void)xz_getObjectsNSArrayI:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    @try {
        [self xz_getObjectsNSArrayI:objects range:range];
    } @catch (NSException *exception) {
    } @finally {
    }
}

@end

2、NSMutableArray Crash:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSMutableArray (XZCrash)

+ (void)xz_enableMutableArrayProtector;

@end

NS_ASSUME_NONNULL_END
#import "NSMutableArray+XZCrash.h"
#import "NSObject+XZSwizzle.h"

@implementation NSMutableArray (XZCrash)


+ (void)xz_enableMutableArrayProtector {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class __NSArrayM = NSClassFromString(@"__NSArrayM");
        
        // objectAtIndex:
        [self xz_instanceSwizzleMethodWithClass:__NSArrayM orginalMethod:@selector(objectAtIndex:) replaceMethod:@selector(xz_objectAtIndex:)];
        
        [self xz_instanceSwizzleMethodWithClass:__NSArrayM orginalMethod:@selector(objectAtIndexedSubscript:) replaceMethod:@selector(xz_objectAtIndexedSubscript:)];

        //insertObject:atIndex:
        [self xz_instanceSwizzleMethodWithClass:__NSArrayM orginalMethod:@selector(insertObject:atIndex:) replaceMethod:@selector(xz_insertObject:atIndex:)];

        //removeObjectAtIndex:
        [self xz_instanceSwizzleMethodWithClass:__NSArrayM orginalMethod:@selector(removeObjectAtIndex:) replaceMethod:@selector(xz_removeObjectAtIndex:)];

        //setObject:atIndexedSubscript:
        [self xz_instanceSwizzleMethodWithClass:__NSArrayM orginalMethod:@selector(setObject:atIndexedSubscript:) replaceMethod:@selector(xz_setObject:atIndexedSubscript:)];

        [self xz_instanceSwizzleMethodWithClass:__NSArrayM orginalMethod:@selector(getObjects:range:) replaceMethod:@selector(xz_getObjects:range:)];
    });
}


- (id)xz_objectAtIndex:(NSUInteger)index {
    id object = nil;
    @try {
        object = [self xz_objectAtIndex:index];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

- (id)xz_objectAtIndexedSubscript:(NSUInteger)index {
    id object = nil;
    @try {
        object = [self xz_objectAtIndex:index];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

- (void)xz_insertObject:(id)anObject atIndex:(NSUInteger)index {
    @try {
        [self xz_insertObject:anObject atIndex:index];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (void)xz_removeObjectAtIndex:(NSUInteger)index {
    @try {
        [self xz_removeObjectAtIndex:index];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (void)xz_setObject:(id)obj atIndexedSubscript:(NSUInteger)idx {
    @try {
        [self xz_setObject:obj atIndexedSubscript:idx];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (void)xz_getObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    @try {
        [self xz_getObjects:objects range:range];
    } @catch (NSException *exception) {
    } @finally {
    }
}

@end

3、NSString Crash:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSString (XZCrash)

+ (void)xz_enableStringProtector;

@end

NS_ASSUME_NONNULL_END
#import "NSString+XZCrash.h"
#import "NSObject+XZSwizzle.h"

@implementation NSString (XZCrash)


+ (void)xz_enableStringProtector {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class __NSCFConstantString = NSClassFromString(@"__NSCFConstantString");
        
        //substringFromIndex
        [self xz_instanceSwizzleMethodWithClass:__NSCFConstantString orginalMethod:@selector(substringFromIndex:) replaceMethod:@selector(xz_substringFromIndex:)];
        
        //substringToIndex
        [self xz_instanceSwizzleMethodWithClass:__NSCFConstantString orginalMethod:@selector(substringToIndex:) replaceMethod:@selector(xz_substringToIndex:)];
        
        //substringWithRange:
        [self xz_instanceSwizzleMethodWithClass:__NSCFConstantString orginalMethod:@selector(substringWithRange:) replaceMethod:@selector(xz_substringWithRange:)];
        
        //characterAtIndex
        [self xz_instanceSwizzleMethodWithClass:__NSCFConstantString orginalMethod:@selector(characterAtIndex:) replaceMethod:@selector(xz_characterAtIndex:)];
        
        /* 注意swizzling先后顺序 : */
        //stringByReplacingOccurrencesOfString:withString:options:range:
        [self xz_instanceSwizzleMethodWithClass:__NSCFConstantString orginalMethod:@selector(stringByReplacingOccurrencesOfString:withString:options:range:) replaceMethod:@selector(xz_stringByReplacingOccurrencesOfString:withString:options:range:)];

        //stringByReplacingCharactersInRange:withString:
        [self xz_instanceSwizzleMethodWithClass:__NSCFConstantString orginalMethod:@selector(stringByReplacingCharactersInRange:withString:) replaceMethod:@selector(xz_stringByReplacingCharactersInRange:withString:)];
    });
}


#pragma mark - characterAtIndex:

- (unichar)xz_characterAtIndex:(NSUInteger)index {
    
    unichar characteristic;
    @try {
        characteristic = [self xz_characterAtIndex:index];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return characteristic;
    }
}

#pragma mark - substringFromIndex:

- (NSString *)xz_substringFromIndex:(NSUInteger)from {
    
    NSString *subString = nil;
    
    @try {
        subString = [self xz_substringFromIndex:from];
    }
    @catch (NSException *exception) {
        subString = nil;
    }
    @finally {
        return subString;
    }
}

#pragma mark - substringToIndex
- (NSString *)xz_substringToIndex:(NSUInteger)index {
    
    NSString *subString = nil;
    
    @try {
        subString = [self xz_substringToIndex:index];
    }
    @catch (NSException *exception) {
        subString = nil;
    }
    @finally {
        return subString;
    }
}

#pragma mark - stringByReplacingCharactersInRange:withString:

- (NSString *)xz_stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement {
    
    NSString *newStr = nil;
    
    @try {
        newStr = [self xz_stringByReplacingCharactersInRange:range withString:replacement];
    }
    @catch (NSException *exception) {
        newStr = nil;
    }
    @finally {
        return newStr;
    }
}

- (NSString *)xz_stringByReplacingOccurrencesOfString:(NSRange)range withString:(NSString *)replacement {
    
    NSString *newStr = nil;
    
    @try {
        newStr = [self xz_stringByReplacingOccurrencesOfString:range withString:replacement];
    }
    @catch (NSException *exception) {
        newStr = nil;
    }
    @finally {
        return newStr;
    }
}

#pragma mark - stringByReplacingOccurrencesOfString:withString:options:range:

- (NSString *)xz_stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange {
    
    NSString *newStr = nil;
    
    @try {
        newStr = [self xz_stringByReplacingOccurrencesOfString:target withString:replacement options:options range:searchRange];
    }
    @catch (NSException *exception) {
        newStr = nil;
    }
    @finally {
        return newStr;
    }
}

#pragma mark - substringWithRange:
- (NSString *)xz_substringWithRange:(NSRange)range {
    
    NSString *subString = nil;
    
    @try {
        subString = [self xz_substringWithRange:range];
    }
    @catch (NSException *exception) {
        subString = nil;
    }
    @finally {
        return subString;
    }
}

@end

4、NSMutableString Crash:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSMutableString (XZCrash)

+ (void)xz_enableMutableStringProtector;

@end

NS_ASSUME_NONNULL_END
#import "NSMutableString+XZCrash.h"
#import "NSObject+XZSwizzle.h"

@implementation NSMutableString (XZCrash)


+ (void)xz_enableMutableStringProtector {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class __NSCFString = NSClassFromString(@"__NSCFString");
        
        //substringFromIndex
        [self xz_instanceSwizzleMethodWithClass:__NSCFString orginalMethod:@selector(substringFromIndex:) replaceMethod:@selector(xz_substringFromIndex:)];
        
        //substringToIndex
        [self xz_instanceSwizzleMethodWithClass:__NSCFString orginalMethod:@selector(substringToIndex:) replaceMethod:@selector(xz_substringToIndex:)];
        
        //substringWithRange:
        [self xz_instanceSwizzleMethodWithClass:__NSCFString orginalMethod:@selector(substringWithRange:) replaceMethod:@selector(xz_substringWithRange:)];
        
        //characterAtIndex
        [self xz_instanceSwizzleMethodWithClass:__NSCFString orginalMethod:@selector(characterAtIndex:) replaceMethod:@selector(xz_characterAtIndex:)];
        
        //replaceCharactersInRange
        [self xz_instanceSwizzleMethodWithClass:__NSCFString orginalMethod:@selector(replaceCharactersInRange:withString:) replaceMethod:@selector(xz_replaceCharactersInRange:withString:)];
        
        //insertString:atIndex:
        [self xz_instanceSwizzleMethodWithClass:__NSCFString orginalMethod:@selector(insertString:atIndex:) replaceMethod:@selector(xz_insertString:atIndex:)];

        //deleteCharactersInRange
        [self xz_instanceSwizzleMethodWithClass:__NSCFString orginalMethod:@selector(deleteCharactersInRange:) replaceMethod:@selector(xz_deleteCharactersInRange:)];
    });
}

#pragma mark - characterAtIndex:

- (unichar)xz_characterAtIndex:(NSUInteger)index {
    
    unichar characteristic;
    @try {
        characteristic = [self xz_characterAtIndex:index];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return characteristic;
    }
}

#pragma mark - substringFromIndex:

- (NSString *)xz_substringFromIndex:(NSUInteger)from {
    
    NSString *subString = nil;
    
    @try {
        subString = [self xz_substringFromIndex:from];
    }
    @catch (NSException *exception) {
        subString = nil;
    }
    @finally {
        return subString;
    }
}

#pragma mark - substringToIndex
- (NSString *)xz_substringToIndex:(NSUInteger)index {
    
    NSString *subString = nil;
    
    @try {
        subString = [self xz_substringToIndex:index];
    }
    @catch (NSException *exception) {
        subString = nil;
    }
    @finally {
        return subString;
    }
}

#pragma mark - substringWithRange:
- (NSString *)xz_substringWithRange:(NSRange)range {
    
    NSString *subString = nil;
    
    @try {
        subString = [self xz_substringWithRange:range];
    }
    @catch (NSException *exception) {
        subString = nil;
    }
    @finally {
        return subString;
    }
}


#pragma mark - replaceCharactersInRange
- (void)xz_replaceCharactersInRange:(NSRange)range withString:(NSString *)aString {
    @try {
        [self xz_replaceCharactersInRange:range withString:aString];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

#pragma mark - insertString:atIndex:
- (void)xz_insertString:(NSString *)aString atIndex:(NSUInteger)loc {
    
    @try {
        [self xz_insertString:aString atIndex:loc];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

#pragma mark - deleteCharactersInRange

- (void)xz_deleteCharactersInRange:(NSRange)range {
    
    @try {
        [self xz_deleteCharactersInRange:range];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

@end

5、NSDictionary Crash:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSDictionary (XZCrash)

+ (void)xz_enableDictionaryProtector;

@end

NS_ASSUME_NONNULL_END
#import "NSDictionary+XZCrash.h"
#import "NSObject+XZSwizzle.h"

@implementation NSDictionary (XZCrash)


+ (void)xz_enableDictionaryProtector {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        // __NSPlaceholderDictionary
        [self xz_classSwizzleMethodWithClass:self orginalMethod:@selector(dictionaryWithObjects:forKeys:count:) replaceMethod:@selector(xz_dictionaryWithObjects:forKeys:count:)];
    });
}

+ (instancetype)xz_dictionaryWithObjects:(const id  _Nonnull __unsafe_unretained *)objects forKeys:(const id  _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt {
    
    id instance = nil;
    @try {
        instance = [self xz_dictionaryWithObjects:objects forKeys:keys count:cnt];
    }
    @catch (NSException *exception) {
        
        //处理错误的数据,然后重新初始化一个字典
        NSUInteger index = 0;
        id  _Nonnull __unsafe_unretained newObjects[cnt];
        id  _Nonnull __unsafe_unretained newkeys[cnt];
        
        for (int i = 0; i < cnt; i++) {
            if (objects[i] && keys[i]) {
                newObjects[index] = objects[i];
                newkeys[index] = keys[i];
                index++;
            }
        }
        instance = [self xz_dictionaryWithObjects:newObjects forKeys:newkeys count:index];
    }
    @finally {
        return instance;
    }
}

@end

6、NSMutableDictionary Crash:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSMutableDictionary (XZCrash)

+ (void)xz_enableMutableDictionaryProtector;

@end

NS_ASSUME_NONNULL_END
#import "NSMutableDictionary+XZCrash.h"
#import "NSObject+XZSwizzle.h"

@implementation NSMutableDictionary (XZCrash)


+ (void)xz_enableMutableDictionaryProtector {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class dictionaryM = NSClassFromString(@"__NSDictionaryM");
        
        //setObject:forKey:
        [self  xz_instanceSwizzleMethodWithClass:dictionaryM orginalMethod:@selector(setObject:forKey:) replaceMethod:@selector(xz_setObject:forKey:)];
        
        // iOS11
        [self xz_instanceSwizzleMethodWithClass:dictionaryM orginalMethod:@selector(setObject:forKeyedSubscript:) replaceMethod:@selector(xz_setObject:forKeyedSubscript:)];

        
        //removeObjectForKey:
        [self xz_instanceSwizzleMethodWithClass:dictionaryM orginalMethod:@selector(removeObjectForKey:) replaceMethod:@selector(xz_removeObjectForKey:)];
    });
}

- (void)xz_setObject:(id)anObject forKey:(id)aKey {
    
    @try {
        [self xz_setObject:anObject forKey:aKey];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (void)xz_setObject:(id)anObject forKeyedSubscript:(id)aKey {
    
    @try {
        [self xz_setObject:anObject forKey:aKey];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (void)xz_removeObjectForKey:(id)aKey {
    
    @try {
        [self xz_removeObjectForKey:aKey];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

@end

7、NSAttributedString Crash:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSAttributedString (XZCrash)

+ (void)xz_enableAttributedStringProtector;

@end

NS_ASSUME_NONNULL_END
#import "NSAttributedString+XZCrash.h"
#import "NSObject+XZSwizzle.h"

@implementation NSAttributedString (XZCrash)


+ (void)xz_enableAttributedStringProtector {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class NSConcreteAttributedString = NSClassFromString(@"NSConcreteAttributedString");
        
        //initWithString:
        [self xz_instanceSwizzleMethodWithClass:NSConcreteAttributedString orginalMethod:@selector(initWithString:) replaceMethod:@selector(xz_initWithString:)];
        //initWithAttributedString
        [self xz_instanceSwizzleMethodWithClass:NSConcreteAttributedString orginalMethod:@selector(initWithAttributedString:) replaceMethod:@selector(xz_initWithAttributedString:)];

        //initWithString:attributes:
        [self xz_instanceSwizzleMethodWithClass:NSConcreteAttributedString orginalMethod:@selector(initWithString:attributes:) replaceMethod:@selector(xz_initWithString:attributes:)];
    });
}


- (instancetype)xz_initWithString:(NSString *)str {
    id object = nil;
    
    @try {
        object = [self xz_initWithString:str];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

#pragma mark - initWithAttributedString
- (instancetype)xz_initWithAttributedString:(NSAttributedString *)attrStr {
    id object = nil;
    
    @try {
        object = [self xz_initWithAttributedString:attrStr];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

#pragma mark - initWithString:attributes:

- (instancetype)xz_initWithString:(NSString *)str attributes:(NSDictionary *)attrs {
    id object = nil;
    
    @try {
        object = [self xz_initWithString:str attributes:attrs];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

@end

8、NSMutableAttributedString Crash:

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSMutableAttributedString (XZCrash)

+ (void)xz_enableMutableAttributedStringProtector;

@end

NS_ASSUME_NONNULL_END
#import "NSMutableAttributedString+XZCrash.h"
#import "NSObject+XZSwizzle.h"

@implementation NSMutableAttributedString (XZCrash)


+ (void)xz_enableMutableAttributedStringProtector {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class NSConcreteMutableAttributedString = NSClassFromString(@"NSConcreteMutableAttributedString");
        
        //initWithString:
        [self xz_instanceSwizzleMethodWithClass:NSConcreteMutableAttributedString orginalMethod:@selector(initWithString:) replaceMethod:@selector(xz_initWithString:)];

        //initWithString:attributes:
        [self xz_instanceSwizzleMethodWithClass:NSConcreteMutableAttributedString orginalMethod:@selector(initWithString:attributes:) replaceMethod:@selector(xz_initWithString:attributes:)];
    });
}


- (instancetype)xz_initWithString:(NSString *)str {
    id object = nil;
    
    @try {
        object = [self xz_initWithString:str];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

- (instancetype)xz_initWithString:(NSString *)str attributes:(NSDictionary *)attrs {
    id object = nil;
    
    @try {
        object = [self xz_initWithString:str attributes:attrs];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

@end

你可能感兴趣的:(iOS崩溃处理机制:Container类型crash防护)