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