获取Class

作者: 学习路上一个远行者 | 来源:发表于2017-08-25 09:54 被阅读25次

    Class

    class本质是一个结构体的指针,结构体是objc_class,这个结构体中包含了:

    • isa (实例->类->meta 类->root meta 类)root meta类指向本身
    • 父类型的指针
    • 类的名字
    • 方法列表(可以是实例方法列表,也可以是类方法列表)
    • 实现的协议列表
    • 版本
    • 保留的信息

    id

    id 本质也是一个结构体的指针,结构体是objc_object这个结构体中包含:
    struct objc_object { Class isa OBJC_ISA_AVAILABILITY; }

    两个获取class的方法:

    +(Class)class
    这是一个类方法,源码是:
    + (Class)class { return self; }
    类方法的class是指向的自己本身,也许你在别人的代码中看见这样的一方法:

    +(void)log {
      [self.class logName];
      // [self logName]; 他们是一个意思
    }
    

    这样当我们需要从一个类的实例对象来获取isa链,那么我们不应该通过这个类方法来获取。

    NSObject *objc = [NSObject new];
    [objc class]; // class
    [[objc class] class];  // meta class
    [[[objc class] class] class]; // root meta class
    

    你的本意是上面的意思,但是这个错误的其实这段代码的含义是这样的:

    NSObject *objc = [NSObject new];
    [objc class]; // class
    [[objc class] class];  // class
    [[[objc class] class] class]; // class
    

    因为类方法+(Class)class返回的是self

    -(Class)class
    实例方法,源码是:
    - (Class)class { return object_getClass(self); }
    我们从这个实例方法中我们可以看出来其实调用的是object_getClass(id)那么这个方法的源码是什么呢?请看下一个章节

    object_getClass

    源码:

    Class object_getClass(id obj)
    {
        if (obj) return obj->getIsa();
        else return Nil;
    }
    

    至于obj_getIsa()这个方法是其实是获取就是获取Class结构体中isa所指向的class指针。你可以通过看源码来了解obj_getIsa()的具体实现,源码

    我们可以通过Class object_getClass(id obj)来获取isa链条

    NSObject *objc = [NSObject new];
    object_getClass(objc); // class
    object_getClass(object_getClass(objc));  //  meta class
    object_getClass(object_getClass(object_getClass(objc))); //root meta class
    

    我的问题

    其实前面的知识,只是我通过看别的博客和简书得知,这里也就是做个记录,现在我要记录一下我疑惑的地方,并且通过做了验证的:

    {
      Class personClass = [Person class];
        NSLog(@"Class------%p", personClass);
        [self logPropertyAndIvarWithClass:personClass];
        
        Person *person = [Person new];
        Class class = person.class;
        NSLog(@"Object------%p", class);
        [self logPropertyAndIvarWithClass:class];
        // 通过实例方法的-(Class)class 和类方法+(Class)class他们指向都是同一个指针,我们知道类在程序中也是一个对象,他们是一个单利。
    }
    
    - (void)logPropertyAndIvarWithClass:(Class)class {
        unsigned int ivarCount = 0;
        Ivar *ivars = class_copyIvarList(class, &ivarCount);
        for (int i = 0 ; i < ivarCount; i++) {
            Ivar ivar = ivars[i];
            NSLog(@"ivar -- %@", [NSString stringWithUTF8String:ivar_getName(ivar)]);
        }
        
        unsigned int propertyCount = 0;
        objc_property_t *properties = class_copyPropertyList(class, &propertyCount);
        for (int i = 0 ; i < propertyCount; i++) {
            objc_property_t property = properties[i];
            NSLog(@"property -- %@", [NSString stringWithUTF8String:property_getName(property)]);
        }
    }
    // 通过上面的两个方法中,我知道ivar 要比property的数量多。
    

    注意:根据runtime获取出来的property,只能是自己本类的property,而不能打印出 继承父类 的property

    相关文章

      网友评论

        本文标题:获取Class

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