runtime -Meta Class

先看一个经常出现的面试题:

@interface NSObject (Test)

- (void)test;

@end
@implementation NSObject (Test)

- (void)test {
    NSLog(@"test")'
}

@end
[NSObject test];
[[[NSObject alloc] init] test];

问题:分别输出什么?

答案:两个都输出的是"test";
之前对使用类对象直接调用方法并且成功输出充满了疑惑,为什么明明一个实例方法-(void)test;确可以使用类对象NSObject直接调用,其实这里就涉及到元类的相关知识;
先看一下网上经常出现的一张图:

MetaClass.png

配合图片理解一下元类的定义:

元类是类对象所属的类,就像类对象是实例对象所属的类一样,反过来说类对象是元类的实例对象,实例方法是存储在类对象里的,类方法是存储在元类对象里面。

这里还应该注意一下根类对象的父类是nil,根类对象的元类是Meta Class,元类的元类是他自身,元类的父类是当前的根类对象。

我们通过代码验证一下:

    Class class = NSClassFromString(@"NSObject");
    Class metaClass = objc_getMetaClass("NSObject");
    Class superClass = class_getSuperclass(class);
    Class metaSuperClass = class_getSuperclass(metaClass);

输出结果:


image.png

由此可见,验证正确。

到此,已经可以看出:
[NSObject test];时,首先会从NSObject的元类中查找+(void)test;方法,在元类中没有找到,接着从元类的父类中查找,在父类中找到,调用成功。

验证一下:

    Class class = NSClassFromString(@"NSObject");
    Class metaClass = objc_getMetaClass("NSObject");
    Class superClass = class_getSuperclass(class);
    Class metaSuperClass = class_getSuperclass(metaClass);
    
    Method method = class_getClassMethod(metaSuperClass, @selector(test));
    NSLog(@"%@",metaClass);
    IMP imp = method_getImplementation(method);
(IMP) imp = 0x0000000106eca4d0 (YDemo`-[NSObject(Test) test] at NSObject+Test.m:13)

这里我获取方法是获取的类方法class_getClassMethod,但是我发现使用class_getInstanceMethod 也获取到test的实例方法,这里有点不明白,我的分类中明明只实现了-(void)test,为什么会同时存在类方法与实例方法,求大佬指点下。

更新

上面最后遗留的问题,为什么通过class_getClassMethodclass_getInstanceMethod 都可以获取到test方法,这里看一下
class_getClassMethod的源码:

Method class_getClassMethod(Class cls, SEL sel)
{
    if (!cls  ||  !sel) return nil;

    return class_getInstanceMethod(cls->getMeta(), sel);
}

其实class_getClassMethod是获取元类的实例方法,所以这里的实例方法[NSObject test];就会变成是class_getInstanceMethod(NSObject->getMeta(), test);到了元类里面其实就是实例方法了。
从这里可以看出在元类中的类方法都是以实例方法存储的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。