美文网首页
iOS实例、类、元类

iOS实例、类、元类

作者: 康小曹 | 来源:发表于2020-11-03 18:07 被阅读0次

    从源码看本质

    源代码:

    @interface XKPerson ()
    
    @property (copy, nonatomic) NSString *name;
    
    @end
    
    @implementation XKPerson
    
    + (instancetype)personWithName:(NSString *)name {
        XKPerson *p = [XKPerson new];
        p.name = name;
        return p;
    }
    

    转化成cpp,整理相关代码:

    // 对象信息的实际存储者
    struct _class_ro_t {
        unsigned int flags;
        unsigned int instanceStart;
        unsigned int instanceSize;
        const unsigned char *ivarLayout;
        const char *name;
        const struct _method_list_t *baseMethods;
        const struct _objc_protocol_list *baseProtocols;
        const struct _ivar_list_t *ivars;
        const unsigned char *weakIvarLayout;
        const struct _prop_list_t *properties;
    };
    
    // 定义了XKPerson的元类
    static struct _class_ro_t _OBJC_METACLASS_RO_$_XKPerson = {
        1, sizeof(struct _class_t), sizeof(struct _class_t), 
        0, 
        "XKPerson",
        (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_XKPerson,
        0, 
        0, 
        0, 
        0, 
    };
    
    // 定义了XKPerson的类对象
    static struct _class_ro_t _OBJC_CLASS_RO_$_XKPerson = {
        0, __OFFSETOFIVAR__(struct XKPerson, _name), sizeof(struct XKPerson_IMPL), 
        0, 
        "XKPerson",
        (const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_XKPerson,
        0, 
        (const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_XKPerson,
        0, 
        0, 
    };
    
    // 对象的管理者
    struct _class_t {
        // 传说中的isa
        struct _class_t *isa;
        // 传说中的superclass
        struct _class_t *superclass;
        // 缓存相关
        void *cache;
        // 暂不使用
        void *vtable;
        // 对象信息的实际保存者
        struct _class_ro_t *ro;
    };
    
    struct _class_t OBJC_METACLASS_$_NSObject;
    
    // 是_class_t,用于管理_XKPerson元类
    struct _class_t OBJC_METACLASS_$_XKPerson = {
        0, // &OBJC_METACLASS_$_NSObject,
        0, // &OBJC_METACLASS_$_NSObject,
        0, // (void *)&_objc_empty_cache,
        0, // unused, was (void *)&_objc_empty_vtable,
        &_OBJC_METACLASS_RO_$_XKPerson,
    };
    
    struct _class_t OBJC_CLASS_$_NSObject;
    
    // 是_class_t,管理XKPerson的类对象
    struct _class_t OBJC_CLASS_$_XKPerson __attribute__ ((used, section ("__DATA,__objc_data"))) = {
        0, // &OBJC_METACLASS_$_XKPerson,
        0, // &OBJC_CLASS_$_NSObject,
        0, // (void *)&_objc_empty_cache,
        0, // unused, was (void *)&_objc_empty_vtable,
        &_OBJC_CLASS_RO_$_XKPerson,
    };
    
    // 真正使用的是_class_t,需要对齐进行初始化
    static void OBJC_CLASS_SETUP_$_XKPerson(void ) {
      // 所有元类的isa指向根源类,也就是metaNSObject
      // metaNSObject的isa指向跟类对象,也就是classNSObject
        OBJC_METACLASS_$_XKPerson.isa = &OBJC_METACLASS_$_NSObject;
      // 元类的superclass指向父元类
        OBJC_METACLASS_$_XKPerson.superclass = &OBJC_METACLASS_$_NSObject;
        OBJC_METACLASS_$_XKPerson.cache = &_objc_empty_cache;
    
      // 类对象的isa指向元类
        OBJC_CLASS_$_XKPerson.isa = &OBJC_METACLASS_$_XKPerson;
      // 类对象的superclass指向父[类对象]
      // 跟类对象(classNSObject)指向为nil,触发消息转发机制
        OBJC_CLASS_$_XKPerson.superclass = &OBJC_CLASS_$_NSObject;
        OBJC_CLASS_$_XKPerson.cache = &_objc_empty_cache;
    }
    
    实例-类对象-元类

    为什么 [[obj class] class] 方法获取不到元类

    实例对象、类对象、元类的获取代码如下:

            NSObject *obj1 = [[NSObject alloc] init];
            NSObject *obj2 = [[NSObject alloc] init];
            NSObject *obj3 = [[NSObject alloc] init];
            
            NSLog(@"instance address:%p %p %p",obj1, obj2, obj3);
            NSLog(@"class address: %p %p %p",[obj1 class], [obj2 class], [obj3 class]);
            NSLog(@"meta class address:%p %p %p",object_getClass([obj1 class]), object_getClass([obj2 class]), object_getClass([obj3 class]));
            NSLog(@"error meta class address:%p %p %p",[[obj1 class] class], [[obj2 class] class], [[obj3 class] class]);
    

    打印结果:

    2020-11-04 09:05:26.264248+0800 XKObjTest[82779:33963605] instance address:0x10285f9a0 0x10285ffb0 0x10285e3d0
    2020-11-04 09:05:26.265428+0800 XKObjTest[82779:33963605] class address: 0x7fff9b7d5140 0x7fff9b7d5140 0x7fff9b7d5140
    2020-11-04 09:05:26.265520+0800 XKObjTest[82779:33963605] meta class address:0x7fff9b7d50f0 0x7fff9b7d50f0 0x7fff9b7d50f0
    2020-11-04 09:05:26.265600+0800 XKObjTest[82779:33963605] error meta class address:0x7fff9b7d5140 0x7fff9b7d5140 0x7fff9b7d5140
    Program ended with exit code: 0
    

    我们都知道[[instance class] class]这样是无法获取到元类的,那原因是什么呢?查找 objc 源码得到 class 方法的源码:

    + (Class)class {
        return self;
    }
    
    - (Class)class {
        return object_getClass(self);
    }
    

    如上图所示,虽然 class 方法本质是调用 object_getClass,但是类方法 class 确是直接返回自己,也就是类对象,所以类对象无论调用多少次 class 方法,返回的都是类对象自己。

    而 object_getClass 的源码如下:

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

    这个方法直接返回的是 isa 指针的指向,所以可以获取到元类;

    相关文章

      网友评论

          本文标题:iOS实例、类、元类

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