美文网首页
包罗万象的runtime(一):对象&类&元类

包罗万象的runtime(一):对象&类&元类

作者: ElaineYin | 来源:发表于2018-06-02 09:56 被阅读5次

    苹果官方维护的objc源代码

    我们常说OC是一种面向对象的语言,那么
    什么是对象?

    :对同一类事物的高度抽象。类定义了这一类的属性以及行为准则(方法)。
    对象:类的一个实例,是一个具体的事物。

    1. runtime中的类和对象

    typedef struct objc_class *Class;
    typedef struct objc_object *id;
    

    简单从定义来看:Class是一个objc_class结构类型的指针,id(任意对象)是一个objc_object结构类型的指针
    再来看下这两个结构体objc_classobjc_object

    /// objc_class
    struct objc_class {
        Class isa;
        Class super_class;
        const char *name;
        long version;
        long info;
        long instance_size;
        struct objc_ivar_list *ivars;
        struct objc_method_list *methodLists;
        struct objc_cache *cache;
        struct objc_protocol_list *protocols;
    } ;
    /// objc_object
    struct objc_object {
        Class isa;
    };
    

    objc_class和objc_object都有一个isa指针,我们知道实例的isa指针指向实例所属的类,即objc_object中的isa指针指向了objc_object所属的类objc_class,那么
    objc_class中的isa指针指向哪里呢

    2. 元类 MetaClass

    先看结论

    每一个类本质上都是一个对象,类其实是元类(meteClass)的实例。类通过类的isa指针指向元类。所有的元类最终继承一个根元类,根元类isa指针指向本身,形成一个封闭的内循环。

    看到这里我又疑惑了,实例的isa指向它所属的类,类的isa指向它的元类,类的元类是什么,是它所继承的父类吗,那么类的isa(元类)和super_class(父类)是不是有关系呢?
    还是要来段代码测试一下:

    Class class1 = [[NSString alloc] init].class;
    Class class = [NSString class];
    Class superClass = [NSString superclass];
    NSLog(@"%@:%p",NSStringFromClass(class1), class1);
    NSLog(@"%@:%p",NSStringFromClass(class), class);
    NSLog(@"%@:%p",NSStringFromClass(superClass), superClass);
    //输出结果
    2018-06-02 08:17:46.802684+0800 RuntimeDemo[1129:82727] __NSCFConstantString:0x108679fe0
    2018-06-02 08:17:46.802851+0800 RuntimeDemo[1129:82727] NSString:0x107abad68
    2018-06-02 08:17:46.802989+0800 RuntimeDemo[1129:82727] NSObject:0x1080feea8
    

    测试发现,NSString的元类([NSString class])并不是我以为的NSObject,而是NSString,那么实例的isa指针和类的isa指针指向到底哪里不一样呢?还是code一下看看吧
    先写个方法输出Class的详细信息

    - (void)getInfoFromClass:(Class)cls {
        /// class_getName 获取类name
        NSLog(@"%s:%p",class_getName(cls), cls);
        /// class_isMetaClass用于判断Class对象是否为元类,
        BOOL isMeta = class_isMetaClass(cls);
        NSLog(@"%@",isMeta?@"是元类":@"不是元类");
        // 成员变量
        unsigned int outCount = 0;
        NSLog(@"成员变量 class_copyIvarList:");
        Ivar *ivars = class_copyIvarList(cls, &outCount);
        for (int i = 0; i < outCount; i++) {
            Ivar ivar = ivars[i];
            NSLog(@"%s",ivar_getName(ivar));
        }
        free(ivars);
        
        // 属性操作
        NSLog(@"属性 class_copyPropertyList:");
        objc_property_t * properties = class_copyPropertyList(cls, &outCount);
        for (int i = 0; i < outCount; i++) {
            objc_property_t property = properties[i];
            NSLog(@"%s", property_getName(property));
        }
        free(properties);
        
        // 方法操作
        NSLog(@"方法 class_copyMethodList:");
        Method *methods = class_copyMethodList(cls, &outCount);
        for (int i = 0; i < outCount; i++) {
            Method method = methods[i];
            SEL sel = method_getName(method);
            NSLog(@"%@",NSStringFromSelector(sel));
        }
        free(methods);
    }
    

    再自定义个Person类(这里为什么不用系统的类呢,因为系统的类方法太多了,输出那么多影响观察)

    #pragma mark - 定义一个类Person
    @interface Person : NSObject
    
    + (void)staticDescription;
    
    - (void)instanceDescription;
    
    @end
    
    @implementation Person
    + (void)staticDescription { }
    
    - (void)instanceDescription { }
    @end
    

    OK,定义了一个类Person,Person包含一个类方法一个实例方法,打印一下看看

    Person *person = [[Person alloc] init];
    /// object_getClass用于获取对象的isa指针指向的对象。
    [self getInfoFromClass:object_getClass(person)];
    [self getInfoFromClass:object_getClass(Person.class)];
    /// 输出结果
    2018-06-02 09:32:32.473784+0800 RuntimeDemo[2398:280748] Person:0x109bf7010
    2018-06-02 09:32:32.473922+0800 RuntimeDemo[2398:280748] 不是元类
    2018-06-02 09:32:32.474260+0800 RuntimeDemo[2398:280748] 方法 class_copyMethodList:
    2018-06-02 09:32:32.474382+0800 RuntimeDemo[2398:280748] instanceDescription
    2018-06-02 09:32:32.474484+0800 RuntimeDemo[2398:280748] Person:0x109bf6fe8
    2018-06-02 09:32:32.474635+0800 RuntimeDemo[2398:280748] 是元类
    2018-06-02 09:32:32.474960+0800 RuntimeDemo[2398:280748] 方法 class_copyMethodList:
    2018-06-02 09:32:32.475084+0800 RuntimeDemo[2398:280748] staticDescription
    

    看到了吧,实例的isa指针指向它所属的类,类的isa指针指向的是类对象的元。类对象存的是关于实例对象的信息(变量,实例方法等),而元类对象(metaclass object)中存储的是关于类的信息(类的版本,名字,类方法等)。

    所以类也是对象,是元类的对象

    类对象和实例对象的区别:尽管类对象保留了一个类实例的原型,但它并不是实例本身。它没有自己的实例变量,也不能执行那些类的实例的方法(只有实例对象才可以执行实例方法)。然而,类的定义能包含那些特意为类对象准备的方法–类方法( 而不是的实例方法)。类对象从父类那里继承类方法,就像实例从父类那里继承实例方法一样。

    来看下说明图:


    image.png

    参考链接:
    https://www.jianshu.com/p/41735c66dccb
    http://justsee.iteye.com/blog/2163905
    http://www.zhimengzhe.com/IOSkaifa/253119.html

    相关文章

      网友评论

          本文标题:包罗万象的runtime(一):对象&类&元类

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