在进入一个新公司时候,接触新的项目。在修改一些界面,而不知这个页面具体是工程中哪个类实现。而必须一个个类页面慢慢的寻找。其实我们可以直接使用RunTime的方法拦截和替换方法来监听页面WillAppear
方法的实现,打印出此类的文件名,而不影响类中原有的方法实现。
创建一个UIViewController
的分类,实现代码后,直接丢入想要的查看的APP项目中,无需#import操作,方便快捷。
#import "UIViewController+LogClassName.h"
#import <objc/runtime.h>
@implementation UIViewController (LogClassName)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class targetClass = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(swizzled_viewWillAppear:);
swizzleMethod(targetClass, originalSelector, swizzledSelector);
});
}
void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector) {
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
IMP swizzledImp = method_getImplementation(swizzledMethod);
char *swizzledTypes = (char *)method_getTypeEncoding(swizzledMethod);
IMP originalImp = method_getImplementation(originalMethod);
char *originalTypes = (char *)method_getTypeEncoding(originalMethod);
BOOL success = class_addMethod(class, originalSelector, swizzledImp, swizzledTypes);
if (success) {
class_replaceMethod(class, swizzledSelector, originalImp, originalTypes);
}else {
// 添加失败,表明已经有这个方法,直接交换
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (void)swizzled_viewWillAppear:(BOOL)animation {
[self swizzled_viewWillAppear:animation];
NSLog(@"\n--------------------------------\n\n<----------------- 此类的名字是( %@ ) ----------------->\n\n--------------------------------\n", NSStringFromClass([self class]));
}
@end
+(void)load{}
方法只要文件存在项目中,方法会在加载类的时候就被调用,也就是 ios 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法。
dispatch_once
保证方法替换只执行一次
class_addMethod:
如果发现方法已经存在,会失败返回,也可以用来做检查用,我们这里是为了避免源方法没有实现的情况;如果方法没有存在,我们则先尝试添加被替换的方法的实现:如果返回成功,说明被替换方法没有存在。被替换的方法没有被实现,我们需要先把这个方法实现,然后再执行我们想要的效果,用我们自定义的方法去替换被替换的方法。
如果返回失败:则说明被替换方法已经存在.直接将两个方法的实现交换即
class_replaceMethod
这个方法.class_replaceMethod
本身会尝试调用class_addMethod
和method_setImplementation
,所以直接调用class_replaceMethod
就可以了)
网友评论