常见crash
- 数组越界
- 插入nil对象
- 无法识别的selector
- 其他异常
数组越界
这里主要由NSArray或者NSMutableArray访问了不在范围内的对象造成的。对于Inmutable数组基本就涉及到一个objectAtIndex:。
NSArray *array = @[@"test"];
id object = array[1];//抛出异常 1.
而对于Mutable数组有修改和删除就主要涉及到setObject:atIndex,insertObject:atIndex:和removeObject:atIndex:来着。
NSMutableArray *mArray = [NSMutableArray arrayWithArray:@[@"test"]];
[mArray insertObject:@"asdf" atIndex:2]; //抛出异常 2.
[mArray removeObejctAtIndex:2]; //异常 3.
插入nil对象
这类问题基本上是出现在数组、字典的初始化中,或者在插入对象时出现。
id obj = nil;
NSArray *array = @[obj,@"test"]; //异常 1
NSString *key = nil;
NSString *value = nil;
NSDictionary *dict = @{key:value}; //异常 2
无法识别的selector
其他异常
针对上面的2个问题,我这里是通过category+swizzle的方式进行的。由于无法识别selector,还没有还一点的正常途径来解决。所以就不说了。这里就弄几段代码。
@implementation NSObject (KLSwizzle)
+ (void) kl_swizzleInstanceSelector:(SEL)originalSelector
withNewSelector:(SEL)newSelector
{
Method originalMethod = class_getInstanceMethod(self, originalSelector);
Method newMethod = class_getInstanceMethod(self, newSelector);
BOOL methodAdded = class_addMethod([self class],
originalSelector,
method_getImplementation(newMethod),
method_getTypeEncoding(newMethod));
if (methodAdded){
class_replaceMethod([self class],
newSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
}else {
method_exchangeImplementations(originalMethod, newMethod);
}
}
+ (void)kl_swizzleClassSelector:(SEL)originalSelector
withNewSelector:(SEL)newSelector{
Method originalMethod = class_getClassMethod(self, originalSelector);
Method newMethod = class_getClassMethod(self, newSelector);
method_exchangeImplementations(originalMethod, newMethod);
}
@end
@implementation NSArray (KLException)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class cls = [[self array] class];
[cls kl_swizzleInstanceSelector:@selector(objectAtIndex:) withNewSelector:KLHookedSel(objectAtIndex:)];
[self kl_swizzleClassSelector:@selector(arrayWithObjects:count:) withNewSelector:KLHookedSel(arrayWithObjects:count:)];
});
}
- (id)KLHookedMethod(objectAtIndex:(NSUInteger)index){
__autoreleasing id instance = nil;
if([self checkRange:index]){
@try{
instance = [self KLHookedMethod(objectAtIndex:)index];
}
@catch (NSException *exception) {
KLLogError(@"exception:%@",exception);
}
}else{
KLLogError(@"catch out of range:%lul in %@ ",(unsigned long)index,self);
}
return instance;
}
- (BOOL)checkRange:(NSUInteger)index{
return [self count] > index;
}
+ (void) _kl_removeObjectFromArray:(const id [])objects at:(NSUInteger) index count:(NSUInteger)cnt{
__unsafe_unretained id* objs = (__unsafe_unretained id*) objects;
for(NSUInteger i=index;i<cnt&&(i+1)<cnt;++i){
objs[i] = objs[i+1];
}
}
+ (instancetype)KLHookedMethod(arrayWithObjects:(const id [])objects count:(NSUInteger)cnt){
NSUInteger count = cnt;
for(NSUInteger i = 0; i < count; ++i){
if(!objects[i]) {
KLLogError(@"insert nil at %d",i);
[self _kl_removeObjectFromArray:objects at:i count:count--];
}
}
return [self KLHookedMethod(arrayWithObjects:objects count:count)];
}
@end
@implementation NSDictionary (KLException)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self kl_swizzleClassSelector:@selector(dictionaryWithObjects:forKeys:count:) withNewSelector:KLHookedSel(dictionaryWithObjects:forKeys:count:)];
});
}
+ (void) _kl_removePairObjects:(const id [])objects keys:(const id <NSCopying> [])keys at:(NSUInteger) index count:(NSUInteger)cnt{
__unsafe_unretained id* objs = (__unsafe_unretained id*) objects;
__unsafe_unretained id* tmpKeys = (__unsafe_unretained id*) keys;
for(NSUInteger i=index;i<cnt&&(i+1)<cnt;++i){
objs[i] = objs[i+1];
}
for(NSUInteger i=index;i<cnt&&(i+1)<cnt;++i){
tmpKeys[i] = tmpKeys[i+1];
}
}
+ (instancetype)KLHookedMethod(dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt){
NSUInteger count = cnt;
for(NSUInteger i = 0; i < count; ++i){
if(!objects[i] || !keys[i]) {
KLLogError(@"insert nil at %d to dictionary",i);
[self _kl_removePairObjects:objects keys:keys at:i count:count--];
}
}
return [self KLHookedMethod(dictionaryWithObjects:objects forKeys:keys count:count)];
}
@end