美文网首页
runtime -Meta Class

runtime -Meta Class

作者: Breezes | 来源:发表于2020-04-18 18:16 被阅读0次

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

@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);到了元类里面其实就是实例方法了。
从这里可以看出在元类中的类方法都是以实例方法存储的。

相关文章

网友评论

      本文标题:runtime -Meta Class

      本文链接:https://www.haomeiwen.com/subject/cklapctx.html