在使用分类(category)对现有类进行功能扩展时,分类中增加的方法会被优先执行,也就是说分类中实现了与原类中某个同名的方法时,在调用的这个方法时调用的是分类中的实现,而不会调用原类中的实现。
分类中的方法会被优先调用是因为在runtime注册类时,会将分类的方法列表插入到类对象方法列表中的前面位置。在调用方法时,会从类对象中的方法缓存列表和方法列表中顺序查找,找到之后就去调用对应的方法实现。所以在查找时会优先查找到分类的方法。
如果希望在调用分类方法时也能调用到原类中对应的同名方法,那么需要通过runtime来读取类对象中的方法列表,然后倒序查询方法并调用。
示例代码如下:
// 原类
@implementation ViewController
- (void)testMethod {
NSLog(@"%@ %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
@end
// Category中的实现
#import "ViewController+test.h"
#import <objc/runtime.h>
@implementation ViewController (test)
- (void)testMethod {
NSLog(@"ViewController+test %@", NSStringFromSelector(_cmd));
unsigned int methodCount;
// 获取类的方法列表
Method *methodList = class_copyMethodList([self class], &methodCount);
for (int i = methodCount - 1; i > 0; i--) {
Method method = methodList[i];
SEL sel = method_getName(method); // 方法名称
IMP imp = method_getImplementation(method); // 指向方法执行地址的指针
NSLog(@"方法名称: %@", [NSString stringWithUTF8String:sel_getName(sel)]);
if (sel == _cmd) {
void (*fundtion)(id, SEL) = (void *)imp;
fundtion(self, sel);
break;
}
}
free(methodList); // 在C语言中但凡用到了 new/creat/copy 这类函数,就要手动释放指针
// 执行任务 (原类中先执行, 如果希望分类的任务先执行,那么这里的任务代码放在testMethod代码块内的前面)
}
网友评论