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

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

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

具体方式:
1、NSArray crash:

#import <Foundation/Foundation.h>

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 <objc/runtime.h>

@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 <Foundation/Foundation.h>

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 <Foundation/Foundation.h>

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 <Foundation/Foundation.h>

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 <Foundation/Foundation.h>

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<NSCopying>  _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 <Foundation/Foundation.h>

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<NSCopying>)aKey {
    
    @try {
        [self xz_setObject:anObject forKey:aKey];
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (void)xz_setObject:(id)anObject forKeyedSubscript:(id<NSCopying>)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 <Foundation/Foundation.h>

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<NSString *,id> *)attrs {
    id object = nil;
    
    @try {
        object = [self xz_initWithString:str attributes:attrs];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

@end

8、NSMutableAttributedString Crash:

#import <Foundation/Foundation.h>

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<NSString *,id> *)attrs {
    id object = nil;
    
    @try {
        object = [self xz_initWithString:str attributes:attrs];
    }
    @catch (NSException *exception) {
    }
    @finally {
        return object;
    }
}

@end
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352