一种有缺点的方法
想拦截object-c类的函数,有一种方法是额外写扩展类,例如下面代码:
@interface UIView(fordebug)
- (void)removeFromSuperview;
@end
@implementation UIView(fordebug)
- (void)removeFromSuperview{
int abcd = 2134;
// [super removeFromSuperview];
}
@end
以上代码丢到你的工程任意的m文件中,就可以拦截UIView.removeFromSuperView函数的调用了。
但是!有一个缺点,
对于私有函数,hook的时候没法调用原函数,例如上面代码的注释行,编译器会报错,因为UIView.removeFromSuperView并没有公开在UIView中,而是声明在UIView(XXX)的扩展类中。
怎么样才能拦截任意类的函数呢?
彻底支持hook的方法
下面介绍另外一种方法。
1. 首先,添加一个新函数作为拦截时候相应的函数:
static void imp_processViewWillAppear(id self, SEL cmd, BOOL animated){
//先执行原来的方法
SEL oriSel = sel_getUid("hook_viewWillAppear:");
void (*hook_viewWillAppear)(id, SEL, BOOL) = (void (*)(id,SEL,BOOL))[UIViewController instanceMethodForSelector:oriSel];//函数指针
hook_viewWillAppear(self,cmd,animated);
do sth。。。
}
2. 然后让被hook的函数指向新函数
methodExchange("UIViewController", "viewWillAppear:", "hook_viewWillAppear:", (IMP)imp_processViewWillAppear);
其中,methodExchange代码:
void methodExchange(const char *className, const char *originalMethodName, const char *replacementMethodName, IMP imp) {
Class cls = objc_getClass(className);//得到指定类的类定义
SEL oriSEL = sel_getUid(originalMethodName);//把originalMethodName注册到RunTime系统中
Method oriMethod = class_getInstanceMethod(cls, oriSEL);//获取实例方法
struct objc_method_description *desc = method_getDescription(oriMethod);//获得指定方法的描述
assert(desc != NULL);
if (desc->types) {
SEL buSel = sel_registerName(replacementMethodName);//把replacementMethodName注册到RunTime系统中
if (class_addMethod(cls, buSel, imp, desc->types)) {//通过运行时,把方法动态添加到类中
Method buMethod = class_getInstanceMethod(cls, buSel);//获取实例方法
method_exchangeImplementations(oriMethod, buMethod);//交换方法
}
}
}
如此,就彻底实现了任意类的拦截响应。
有没有更好的?
个人推理,以上两种方法应该是可以结合使用,例如正常的对于私有的函数,再使用以下方法进行调用原函数:
@interface UIView(fordebug)
- (void)removeFromSuperview;
@end
@implementation UIView(fordebug)
- (void)removeFromSuperview{
int abcd = 2134;
// [super removeFromSuperview];
执行原来的方法
SEL oriSel = sel_getUid("removeFromSuperview");
void (*hook_removeFromSuperview)(id, SEL, BOOL) = (void (*)(id,SEL,BOOL))[UIView instanceMethodForSelector:oriSel];//函数指针
hook_removeFromSuperview(self,cmd);
}
@end
不过这种方法没验证过,理论上评估是可以,读者可以自行试试,
有问题,随时联系,加扣扣群,或者留言。
本文结束。