今天項(xiàng)目上的一個(gè)功能頻繁出現(xiàn)數(shù)組越界導(dǎo)致閃退的情況,這個(gè)功能上許多地方用了NSArray的objectAtIndex:
方法,于是我想著用Method Swizzing 來hook一下這個(gè)方法,加上防越界判斷,代碼如下:
+(void)load{
static dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
Method m1 = class_getInstanceMethod([self class], @selector(objectAtIndex:));
Method m2 = class_getInstanceMethod([self class], @selector(My_objectAtIndex:));
BOOL isAdd = class_addMethod([self class], @selector(objectAtIndex:), method_getImplementation(m2), method_getTypeEncoding(m2));
if (isAdd == YES) {
class_replaceMethod([self class], @selector(My_objectAtIndex:), method_getImplementation(m1), method_getTypeEncoding(m1));
}else{
method_exchangeImplementations(m1, m2);
}
});
}
-(id)My_objectAtIndex:(NSUInteger)index{
NSLog(@"exchangeSuccess");
return [self My_objectAtIndex:index];
}
因?yàn)閷戇^許多次Method Swizzing,所以我對這份代碼挺有信心的,但是實(shí)際運(yùn)行的時(shí)候,objectAtIndex
和My_objectAtIndex
沒有調(diào)換過來。
然后我檢查了無數(shù)次代碼,嘗試了無數(shù)次可能,沒有任何進(jìn)展。
最后我開始懷疑是不是這個(gè)方法不支持hook,于是我hook了lastObject
方法,lastObject
方法。
+(void)load{
static dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
Method m1 = class_getInstanceMethod([self class], @selector(lastObject));
Method m2 = class_getInstanceMethod([self class], @selector(My_lastObject));
BOOL isAdd = class_addMethod([self class], @selector(lastObject), method_getImplementation(m2), method_getTypeEncoding(m2));
if (isAdd == YES) {
class_replaceMethod([self class], @selector(My_lastObject), method_getImplementation(m1), method_getTypeEncoding(m1));
}else{
method_exchangeImplementations(m1, m2);
}
Method m3 = class_getInstanceMethod([self class], @selector(firstObject));
Method m4 = class_getInstanceMethod([self class], @selector(My_fistObjcet));
method_exchangeImplementations(m3, m4);
});
}
-(id)My_fistObjcet{
NSLog(@"My_fistObjcet : exchangeSuccess");
return [self My_fistObjcet];
}
-(id)My_lastObject{
NSLog(@"My_lastObject : exchangeSuccess");
return [self My_lastObject];
}
兩個(gè)方法的Method swizzing都成功了。然后在My_lastObject上打斷點(diǎn)的時(shí)候發(fā)現(xiàn),在用ObjectAtIndex的時(shí)候,也調(diào)用了lastObject。
我又去嘗試Method swizzing了幾個(gè)用到Index的方法,而且都調(diào)用了lastObject,我查閱了一些文檔,發(fā)現(xiàn)都是擦邊講到相關(guān)內(nèi)容,大概原因是因?yàn)閮?nèi)部算法的限制,導(dǎo)致了用到Index的方法,大部分不支持Method Swizzing 。
因?yàn)橛昧吮容^久的時(shí)間去糾結(jié),所以覺得有必要在這里Mark出這個(gè)坑。
----------- 分割線 ---------------
在大神們的幫助下找到了原因,并不是這里不支持Method Swizzing,而是我用錯了類名 。之前用了 __NSArray0 試過沒效果,以為是沒什么關(guān)系的,也是因?yàn)樽陨淼闹R局限。后面用__NSArrayM,__NSArrayI便可以了。
Method m1 = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), @selector(objectAtIndex:));
Method m2 = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), @selector(My_objectAtIndex:));
我嘗試去翻之前看的文章,但是找不到了。
因?yàn)槲恼率怯⑽牡?,所以我可能有些理解錯誤。里面有一句“NSArray can not do this directly?!?這里的do this 是指Method Swizzing,現(xiàn)在想應(yīng)該是說只不能直接用[self class]吧。