Container类型crash防护(Container)

Container crash 产生原因

Container 类型的crash 指的是容器类的crash,常见的有NSArray/NSMutableArray/NSDictionary/NSMutableDictionary/NSCache的crash。 一些常见的越界,插入nil,等错误操作均会导致此类crash发生。 由于产生的原因比较简单,就不展开来描述了。

该类crash虽然比较容易排查,但是其在app crash概率总比还是挺高,所以有必要对其进行防护。

Container crash 防护方案

Container crash 类型的防护方案也比较简单,针对于NSArray/NSMutableArray/NSDictionary/NSMutableDictionary/NSCache的一些常用的会导致崩溃的API进行method swizzling,然后在swizzle的新方法中加入一些条件限制和判断,从而让这些API变的安全如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[self swizzlingInstance:objc_getClass("__NSPlaceholderDictionary") orginalMethod:@selector(initWithObjects:forKeys:count:) replaceMethod:NSSelectorFromString(@"qiye_initWithObjects:forKeys:count:")];
[self swizzlingInstance:objc_getClass("__NSPlaceholderDictionary") orginalMethod:@selector(dictionaryWithObjects:forKeys:count:) replaceMethod:NSSelectorFromString(@"qiye_dictionaryWithObjects:forKeys:count:")];
[self swizzlingInstance:objc_getClass("__NSDictionaryM") orginalMethod:@selector(setObject:forKey:) replaceMethod:NSSelectorFromString(@"qiye_setObject:forKey:")];
[self swizzlingInstance:objc_getClass("__NSPlaceholderArray") orginalMethod:@selector(initWithObjects:count:) replaceMethod:NSSelectorFromString(@"qiye_initWithObjects:count:")];
[self swizzlingInstance:objc_getClass("__NSArrayI") orginalMethod:@selector(objectAtIndex:) replaceMethod:NSSelectorFromString(@"qiye_objectAtIndex:")];
[self swizzlingInstance:objc_getClass("__NSArrayM") orginalMethod:@selector(addObject:) replaceMethod:NSSelectorFromString(@"qiye_addObject:")];
[self swizzlingInstance:objc_getClass("__NSArrayM") orginalMethod:@selector(insertObject:atIndex:) replaceMethod:NSSelectorFromString(@"qiye_insertObject:atIndex:")];
[self swizzlingInstance:objc_getClass("__NSArrayM") orginalMethod:@selector(objectAtIndex:) replaceMethod:NSSelectorFromString(@"qiye_objectAtIndex:")];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
+(BOOL)swizzlingInstance:(Class)clz orginalMethod:(SEL)originalSelector replaceMethod:(SEL)replaceSelector{
Method original = class_getInstanceMethod(clz, originalSelector);
Method replace = class_getInstanceMethod(clz, replaceSelector);
BOOL didAddMethod =
class_addMethod(clz,
originalSelector,
method_getImplementation(replace),
method_getTypeEncoding(replace));
if (didAddMethod) {
class_replaceMethod(clz,
replaceSelector,
method_getImplementation(original),
method_getTypeEncoding(original));
} else {
method_exchangeImplementations(original, replace);
}
return YES;
}