Objective-C中方法被加载到method_list中真实情况

前言

我们在面试有关分类的有关方法的时候都知道如下的两个知识点:

  1. 同名的方法,分类会替换主类中的方法
  2. 如果多个分类有同名的方法,那么这个方法是随机调用的

理论基础:

runtime加载类的时候,会先加载类(先去递归加载其父类),后加载所有的Category.

Objective-C Automatic Reference Counting (ARC)中也有类似的描述:

Categories allow methods (but not ivars) to be declared post hoc on an arbitrary class; the methods in the category’s @implementation will be dynamically added to that class’s method tables which the category is loaded at runtime, replacing those methods in case of a collision.

Category中的方法在冲突的时候会发生替换

验证

输出一个类的方法列表RXRuntimeUtil中:

+ (void)printMethodListWithClass:(Class)cls
{
    NSMutableArray *array = [NSMutableArray new];
    [array addObject:@""];
    [array addObject:@"method list:"];
    [array addObject:@"methodName address"];
    unsigned int count;
    Method *methodList = class_copyMethodList(cls, &count);
    for (unsigned int i = 0; i < count; i++) {
        Method method = methodList[i];
        NSString *methodName = NSStringFromSelector(method_getName(method));
        IMP methodIMP = method_getImplementation(method);
        NSString *str = [NSString stringWithFormat:@"%@ %p", methodName, methodIMP];
        [array addObject:str];
    }
    NSLog(@"%@", [array componentsJoinedByString:@"\n"]);
}

定义一个父类:RXARCCategoryMethodParentObject

@implementation RXARCCategoryMethodParentObject
- (void)print
{
    NSLog(@"RXARCCategoryMethodParentObject");
}
@end

定义一个子类RXARCCategoryMethodSubObject继承于RXARCCategoryMethodParentObject

@implementation RXARCCategoryMethodSubObject
- (void)print
{
    NSLog(@"RXARCCategoryMethodSubObject");
}
@end

给刚刚那个子类定义两个Category

@implementation RXARCCategoryMethodSubObject (C1)
- (void)print
{
    NSLog(@"C1");
}
@end

@implementation RXARCCategoryMethodSubObject (C2)
- (void)print
{
    NSLog(@"C2");
}
@end

测试代码:

- (void)_test_category_method
{
    [RXRuntimeUtil printMethodListWithClass:[RXARCCategoryMethodParentObject class]];
    [RXRuntimeUtil printMethodListWithClass:[RXARCCategoryMethodSubObject class]];
}

测试结果:

method list:
methodName address
print 0x10d04b8c0
method list:
methodName address
print 0x10d020a00
print 0x10d01e960
print 0x10cfe96d0

结论

在测试结果中发现,居然出现了3个print函数,这3个分别是:
子类的,C1分类的,C2分类的,跟父类的那个没有关系,父类的是在Parent的方法表中。
猜测是:也许以前的版本是替换,现在的版本是追加了,根据消息发送机制,只不过会优先搜索到Category中的方法而已,实际上的主类中那个方法依然存在。

猜你喜欢

转载自blog.csdn.net/weixin_34111790/article/details/87492784
今日推荐