Method Swizzling 代码
+(void)lh_methodSwizzWithCls:(Class)cls clsSeletor:(SEL)clsSel swizzedSel:(SEL)swizzedSel{
Method clsMetod = class_getInstanceMethod(cls, clsSel);
Method swizzedMethod = class_getInstanceMethod(cls, swizzedSel);
if (!cls || !clsMetod || !swizzedMethod) return;//判断是否存在要hook的方法(包括父类)
BOOL addSuccessful = class_addMethod(cls, clsSel, method_getImplementation(swizzedMethod), method_getTypeEncoding(swizzedMethod));//防止子类中没有重写父类方法或者不存在此方法。
if (addSuccessful) {
class_replaceMethod(cls, swizzedSel, method_getImplementation(clsMetod), method_getTypeEncoding(clsMetod));//获取父类imp并且替换 swizzedSel 对应的imp.
}else{
method_exchangeImplementations(clsMetod, swizzedMethod);
}
}
在NSArray 和NSMutableArray load方法中实现hook。
在NSArray分类中代码实现如下:
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString* arrayZeroStr = @"__NSArray0"; //真身 NSArray*arr0 = [[NSArray alloc]init];
NSString* arraySingleStr = @"__NSSingleObjectArrayI";//真身 NSArray*arr1 = @[@"0"];
NSString* arrayStr = @"__NSArrayI";// NSArray*arr2 = @[@"0",@"1"]; objets>时类的真身
[NSObject lh_methodSwizzWithCls:NSClassFromString(arrayZeroStr) clsSeletor:@selector(objectAtIndex:) swizzedSel:@selector(lh_safeArrZero_objectAtIndex:)];
[NSObject lh_methodSwizzWithCls:NSClassFromString(arraySingleStr) clsSeletor:@selector(objectAtIndex:) swizzedSel:@selector(lh_safeArrSingle_objectAtIndex:)];
[NSObject lh_methodSwizzWithCls:NSClassFromString(arrayStr) clsSeletor:@selector(objectAtIndex:) swizzedSel:@selector(lh_safeArr_objectAtIndex:)];
});
}
-(id)lh_safeArrZero_objectAtIndex:(NSInteger)index{
if (self.count<=index) {
NSLog(@"数组越界");
return nil;
}
return [self lh_safeArrZero_objectAtIndex:index];
}
-(id)lh_safeArrSingle_objectAtIndex:(NSInteger)index{
if (self.count<=index) {
NSLog(@"数组越界");
return nil;
}
return [self lh_safeArrSingle_objectAtIndex:index];
}
-(id)lh_safeArr_objectAtIndex:(NSInteger)index{
if (self.count<=index) {
NSLog(@"数组越界");
return nil;
}
return [self lh_safeArr_objectAtIndex:index];
}
NSMutableArray分类中代码实现如下:
+(void)load{
// [super load];
static dispatch_once_t onceToken;//确保只执行一次
dispatch_once(&onceToken, ^{
[NSObject lh_methodSwizzWithCls:NSClassFromString(@"__NSArrayM") clsSeletor:@selector(objectAtIndex:) swizzedSel:@selector(lh_safe_MArr_objAtIndex:)];
[NSObject lh_methodSwizzWithCls:NSClassFromString(@"__NSArrayM") clsSeletor:@selector(objectAtIndexedSubscript:) swizzedSel:@selector(lh_safeMArr_objectAtIndexedSubscript:)];
});
}
-(id)lh_safe_MArr_objAtIndex:(NSInteger)index{
if (index>=self.count) {
NSLog(@"可变数组下标越界");
return nil;
}
return [self lh_safe_MArr_objAtIndex:index];
}
-(id)lh_safeMArr_objectAtIndexedSubscript:(NSInteger)index{
if (index >= self.count) {
NSLog(@"可变数组下标越界");
return nil;
}
return [self lh_safeMArr_objectAtIndexedSubscript:index];
}